# Essential libraries
library(corrplot)
library(ggeffects)
library(ggplot2)
library(DHARMa)
library(glmmTMB)
library(dplyr)
library(lubridate)
library(emmeans)
library(tidyverse)
library(performance)

1. Data Import and Preparation

df <- read.csv("./data/Mock_Mosquito_MixedEffects_w_slopes_Dataset.csv")
df$Trap_type = factor(df$Trap_type)
df$Mosquito_species = factor(df$Mosquito_species)
head(df)

2. Model Specification

Defining Random Effects

We start by first defining the random effects part. There are two random effects defined in our model, one for the nested structure in our data and the other for the mosquito species. By defining random intercepts in m1 model, we assume that different cities have different baseline abundance levels, different sites within the same city have different baseline abundance, and different mosquito species have different baseline abundance levels. However, the slopes remain consistent meaning all cities and species respond to green coverage the same way.

m1_baseline <- glmmTMB(
  Mosquito_abundance ~ Green_area_coverage * Trap_type +
                       Temperature * Relative_humidity +
                       Host_abundance * Predator_abundance +
                       Blue_area_coverage +
                       factor(Month) +
                       (1 | City / Location.Site) +      # nested random effects
                       (1 | Mosquito_species),           # random intercept by species
  family = nbinom2(),
  data = df,
  REML = TRUE
)

summary(m1_baseline)
 Family: nbinom2  ( log )
Formula:          Mosquito_abundance ~ Green_area_coverage * Trap_type + Temperature *  
    Relative_humidity + Host_abundance * Predator_abundance +  
    Blue_area_coverage + factor(Month) + (1 | City/Location.Site) +      (1 | Mosquito_species)
Data: df

      AIC       BIC    logLik -2*log(L)  df.resid 
  18366.2   18515.3   -9157.1   18314.2      2262 

Random effects:

Conditional model:
 Groups             Name        Variance Std.Dev.
 Location.Site:City (Intercept) 0.12116  0.3481  
 City               (Intercept) 0.12336  0.3512  
 Mosquito_species   (Intercept) 0.05108  0.2260  
Number of obs: 2288, groups:  Location.Site:City, 54; City, 6; Mosquito_species, 5

Dispersion parameter for nbinom2 family (): 1.98 

Conditional model:
                                         Estimate Std. Error z value Pr(>|z|)    
(Intercept)                            -1.867e+00  7.967e-01  -2.344 0.019084 *  
Green_area_coverage                     8.413e-03  2.284e-03   3.683 0.000231 ***
Trap_typeLight_CO2                      1.175e-01  7.294e-02   1.611 0.107204    
Temperature                             7.078e-02  3.399e-02   2.082 0.037300 *  
Relative_humidity                       3.435e-02  8.128e-03   4.226 2.38e-05 ***
Host_abundance                          2.017e-02  9.056e-03   2.227 0.025963 *  
Predator_abundance                      2.250e-03  6.004e-03   0.375 0.707912    
Blue_area_coverage                      6.065e-03  3.833e-03   1.583 0.113513    
factor(Month)2                         -5.252e-02  8.426e-02  -0.623 0.533063    
factor(Month)3                          1.012e-01  9.255e-02   1.093 0.274366    
factor(Month)4                          1.588e-01  1.064e-01   1.492 0.135757    
factor(Month)5                          3.574e-01  1.201e-01   2.975 0.002934 ** 
factor(Month)6                          2.764e-01  1.308e-01   2.113 0.034565 *  
factor(Month)7                          3.973e-01  1.215e-01   3.270 0.001075 ** 
factor(Month)8                          1.085e-01  1.059e-01   1.025 0.305318    
factor(Month)9                          1.525e-01  9.086e-02   1.678 0.093279 .  
factor(Month)10                         8.593e-02  8.213e-02   1.046 0.295435    
factor(Month)11                         3.149e-04  7.928e-02   0.004 0.996830    
factor(Month)12                        -1.800e-03  8.171e-02  -0.022 0.982421    
Green_area_coverage:Trap_typeLight_CO2  5.819e-03  1.265e-03   4.599 4.26e-06 ***
Temperature:Relative_humidity          -8.019e-04  4.515e-04  -1.776 0.075746 .  
Host_abundance:Predator_abundance       1.507e-05  1.160e-04   0.130 0.896639    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
baseline_aic <- AIC(m1_baseline)
cat("Baseline AIC:", baseline_aic, "\n")
Baseline AIC: 18366.19 

In the second model, we consider random slopes for green levels in the cities, meaning that the effect of urban green differs per city.

m2_city_green <- glmmTMB(
  Mosquito_abundance ~ Green_area_coverage * Trap_type +
                       Temperature * Relative_humidity +
                       Host_abundance * Predator_abundance +
                       Blue_area_coverage +
                       factor(Month) +
                      (1 + Green_area_coverage | City) +          # City random intercept + slope
                      (1 | Location.Site:City) +        
                      (1 | Mosquito_species),
  family = nbinom2(),
  data = df,
  REML =TRUE
)


# Check convergence
check_convergence(m2_city_green)
[1] TRUE
m2_city_green$sdr$pdHess
[1] TRUE
cat("AIC difference:", AIC(m2_city_green) - baseline_aic, "\n")
AIC difference: -2.716824 
lrt_m2 <- anova(m1_baseline, m2_city_green)$Chisq[2]

p_m2 <- 0.5 * pchisq(lrt_m2, df = 2, lower.tail = FALSE) + 
           0.5 * pchisq(lrt_m2, df = 1, lower.tail = FALSE)
cat("p-value:", p_m2, "\n")
p-value: 0.02217061 

AIC difference is negative and the \(H_0: \text{Cities do not differ in how urban green level affects mosquito abundance}\) is rejected (p<0.05), the random slope of urban green level is significant.

m3_city_temp <- glmmTMB(
  Mosquito_abundance ~ Green_area_coverage * Trap_type +
                       Temperature * Relative_humidity +
                       Host_abundance * Predator_abundance +
                       Blue_area_coverage +
                       factor(Month) +
                      (1 + Temperature | City) +      
                      (1 | Location.Site:City) +        
                      (1 | Mosquito_species),
  family = nbinom2(),
  data = df,
  REML = TRUE
)

# Check convergence
check_convergence(m3_city_temp)
[1] FALSE
m3_city_temp$sdr$pdHess
[1] TRUE
cat("AIC difference:", AIC(m3_city_temp) - baseline_aic, "\n")
AIC difference: 3.928898 
lrt_m3 <- anova(m1_baseline, m3_city_temp)$Chisq[2]

p_m3 <- 0.5 * pchisq(lrt_m3, df = 2, lower.tail = FALSE) +
        0.5 * pchisq(lrt_m3, df = 1, lower.tail = FALSE)
cat("p-value for Temp slope:", p_m3, "\n")
p-value for Temp slope: 0.8774065 

AIC difference is positive and the \(H_0: \text{Cities do not differ in how temperature affects mosquito abundance}\) is retained (p>0.05), the random slope of temperature is not significant.

m4_both_slopes <- glmmTMB(
  Mosquito_abundance ~ Green_area_coverage * Trap_type +
                       Temperature * Relative_humidity +
                       Host_abundance * Predator_abundance +
                       Blue_area_coverage +
                       factor(Month) +
                       (1 + Green_area_coverage + Temperature | City) +
                       (1 | Location.Site:City) +
                       (1 | Mosquito_species),
  family = nbinom2(),
  data = df,
  REML = TRUE
)

# Check convergence
check_convergence(m4_both_slopes)
[1] FALSE
m4_both_slopes$sdr$pdHess
[1] TRUE
# Compare m2 -> m4 (does adding temperature slope to m2 improve fit?)
lrt_m2_m4 <- anova(m2_city_green, m4_both_slopes)$Chisq[2]
cat("LRT stat (m2 -> m4):", lrt_m2_m4, "\n")
LRT stat (m2 -> m4): 0.204401 
p_m2_m4 <- 0.5 * pchisq(lrt_m2_m4, df = 2, lower.tail = FALSE) + 
           0.5 * pchisq(lrt_m2_m4, df = 1, lower.tail = FALSE)
cat("p-value (m2 -> m4):", p_m2_m4, "\n")
p-value (m2 -> m4): 0.7770201 
# Compare m3 -> m4 (does adding Green slope to m3 improve fit?)
lrt_m3_m4 <- anova(m3_city_temp, m4_both_slopes)$Chisq[2]
cat("LRT stat (m3 -> m4):", lrt_m3_m4, "\n")
LRT stat (m3 -> m4): 6.850123 
p_m3_m4 <- 0.5 * pchisq(lrt_m3_m4, df = 2, lower.tail = FALSE) + 
           0.5 * pchisq(lrt_m3_m4, df = 1, lower.tail = FALSE)
cat("p-value (m3 -> m4):", p_m3_m4, "\n")
p-value (m3 -> m4): 0.0207054 
# Compare all models by AIC 
models <- list(m1_baseline = m1_baseline, m2 = m2_city_green, m3 = m3_city_temp, m4 = m4_both_slopes)
aic_tab <- data.frame(
  model = names(models),
  AIC = sapply(models, AIC),
  pdHess = sapply(models, function(m) { if (is.null(m$sdr)) NA else m$sdr$pdHess })
)
aic_tab <- aic_tab %>% arrange(AIC)
print(aic_tab)

Across the models tested, the lowest AIC value was tested was achieved by model 2, for the remainder of the model selection procedure we will use the random effects defined in model 2. Now, we will focus on getting a more parsimonious fixed effects part by removing interaction terms in a step wise manner.

m_full <- glmmTMB(
  Mosquito_abundance ~ Green_area_coverage * Trap_type +
                       Temperature * Relative_humidity +
                       Host_abundance * Predator_abundance +
                       Blue_area_coverage +
                       factor(Month) +
                       (1 + Green_area_coverage | City) +          # City random intercept + slope
                      (1 | Location.Site:City) +        
                      (1 | Mosquito_species),
  family = nbinom2(),
  data = df,
  REML = FALSE  # ML for fixed effects comparison
)

summary(m_full)
 Family: nbinom2  ( log )
Formula:          Mosquito_abundance ~ Green_area_coverage * Trap_type + Temperature *  
    Relative_humidity + Host_abundance * Predator_abundance +  
    Blue_area_coverage + factor(Month) + (1 + Green_area_coverage |  
    City) + (1 | Location.Site:City) + (1 | Mosquito_species)
Data: df

      AIC       BIC    logLik -2*log(L)  df.resid 
  18216.1   18376.7   -9080.0   18160.1      2260 

Random effects:

Conditional model:
 Groups             Name                Variance  Std.Dev. Corr  
 City               (Intercept)         6.083e-02 0.246641       
                    Green_area_coverage 3.707e-05 0.006088 -0.37 
 Location.Site:City (Intercept)         8.948e-02 0.299125       
 Mosquito_species   (Intercept)         4.596e-02 0.214383       
Number of obs: 2288, groups:  City, 6; Location.Site:City, 54; Mosquito_species, 5

Dispersion parameter for nbinom2 family ():    2 

Conditional model:
                                         Estimate Std. Error z value Pr(>|z|)    
(Intercept)                            -1.862e+00  7.828e-01  -2.379 0.017359 *  
Green_area_coverage                     7.260e-03  3.286e-03   2.209 0.027153 *  
Trap_typeLight_CO2                      1.245e-01  7.270e-02   1.713 0.086802 .  
Temperature                             6.912e-02  3.385e-02   2.042 0.041182 *  
Relative_humidity                       3.430e-02  8.095e-03   4.237 2.27e-05 ***
Host_abundance                          2.047e-02  8.994e-03   2.276 0.022868 *  
Predator_abundance                      2.477e-03  5.961e-03   0.415 0.677825    
Blue_area_coverage                      7.381e-03  3.584e-03   2.060 0.039431 *  
factor(Month)2                         -4.997e-02  8.398e-02  -0.595 0.551836    
factor(Month)3                          1.074e-01  9.227e-02   1.164 0.244285    
factor(Month)4                          1.671e-01  1.062e-01   1.574 0.115443    
factor(Month)5                          3.700e-01  1.198e-01   3.088 0.002016 ** 
factor(Month)6                          2.886e-01  1.304e-01   2.213 0.026866 *  
factor(Month)7                          4.082e-01  1.212e-01   3.368 0.000757 ***
factor(Month)8                          1.170e-01  1.056e-01   1.108 0.268040    
factor(Month)9                          1.577e-01  9.056e-02   1.741 0.081608 .  
factor(Month)10                         8.754e-02  8.185e-02   1.070 0.284832    
factor(Month)11                         5.986e-04  7.900e-02   0.008 0.993954    
factor(Month)12                        -1.046e-03  8.141e-02  -0.013 0.989752    
Green_area_coverage:Trap_typeLight_CO2  5.691e-03  1.262e-03   4.511 6.45e-06 ***
Temperature:Relative_humidity          -7.912e-04  4.496e-04  -1.760 0.078454 .  
Host_abundance:Predator_abundance       1.126e-05  1.152e-04   0.098 0.922116    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

We start by removing the least significant interaction term which is Host_abundance:Predator_abundance .

m_wo_host_pre <- glmmTMB(
  Mosquito_abundance ~ Green_area_coverage * Trap_type +
                       Temperature * Relative_humidity +
                       Host_abundance + Predator_abundance +
                       Blue_area_coverage +
                       factor(Month) +
                       (1 + Green_area_coverage | City) +          # City random intercept + slope
                      (1 | Location.Site:City) +        
                      (1 | Mosquito_species),
  family = nbinom2(),
  data = df,
  REML = FALSE  # ML for fixed effects comparison
)

summary(m_wo_host_pre)
 Family: nbinom2  ( log )
Formula:          Mosquito_abundance ~ Green_area_coverage * Trap_type + Temperature *  
    Relative_humidity + Host_abundance + Predator_abundance +  
    Blue_area_coverage + factor(Month) + (1 + Green_area_coverage |  
    City) + (1 | Location.Site:City) + (1 | Mosquito_species)
Data: df

      AIC       BIC    logLik -2*log(L)  df.resid 
  18214.1   18369.0   -9080.0   18160.1      2261 

Random effects:

Conditional model:
 Groups             Name                Variance  Std.Dev. Corr  
 City               (Intercept)         6.066e-02 0.246290       
                    Green_area_coverage 3.711e-05 0.006092 -0.37 
 Location.Site:City (Intercept)         8.961e-02 0.299345       
 Mosquito_species   (Intercept)         4.597e-02 0.214411       
Number of obs: 2288, groups:  City, 6; Location.Site:City, 54; Mosquito_species, 5

Dispersion parameter for nbinom2 family ():    2 

Conditional model:
                                         Estimate Std. Error z value Pr(>|z|)    
(Intercept)                            -1.9033561  0.6709093  -2.837 0.004554 ** 
Green_area_coverage                     0.0072419  0.0032831   2.206 0.027399 *  
Trap_typeLight_CO2                      0.1243781  0.0726983   1.711 0.087103 .  
Temperature                             0.0690642  0.0349110   1.978 0.047896 *  
Relative_humidity                       0.0342986  0.0082954   4.135 3.56e-05 ***
Host_abundance                          0.0213223  0.0021267  10.026  < 2e-16 ***
Predator_abundance                      0.0030338  0.0017445   1.739 0.082024 .  
Blue_area_coverage                      0.0074033  0.0035795   2.068 0.038618 *  
factor(Month)2                         -0.0501047  0.0839359  -0.597 0.550547    
factor(Month)3                          0.1074290  0.0921659   1.166 0.243775    
factor(Month)4                          0.1675267  0.1060089   1.580 0.114037    
factor(Month)5                          0.3701742  0.1199362   3.086 0.002026 ** 
factor(Month)6                          0.2887538  0.1304774   2.213 0.026894 *  
factor(Month)7                          0.4082087  0.1213271   3.365 0.000767 ***
factor(Month)8                          0.1170888  0.1055235   1.110 0.267172    
factor(Month)9                          0.1578000  0.0904607   1.744 0.081089 .  
factor(Month)10                         0.0876332  0.0818319   1.071 0.284218    
factor(Month)11                         0.0006265  0.0790036   0.008 0.993673    
factor(Month)12                        -0.0008575  0.0813868  -0.011 0.991593    
Green_area_coverage:Trap_typeLight_CO2  0.0056932  0.0012615   4.513 6.38e-06 ***
Temperature:Relative_humidity          -0.0007906  0.0004658  -1.697 0.089621 .  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
anova(m_full, m_wo_host_pre)
Data: df
Models:
m_wo_host_pre: Mosquito_abundance ~ Green_area_coverage * Trap_type + Temperature * , zi=~0, disp=~1
m_wo_host_pre:     Relative_humidity + Host_abundance + Predator_abundance + , zi=~0, disp=~1
m_wo_host_pre:     Blue_area_coverage + factor(Month) + (1 + Green_area_coverage | , zi=~0, disp=~1
m_wo_host_pre:     City) + (1 | Location.Site:City) + (1 | Mosquito_species), zi=~0, disp=~1
m_full: Mosquito_abundance ~ Green_area_coverage * Trap_type + Temperature * , zi=~0, disp=~1
m_full:     Relative_humidity + Host_abundance * Predator_abundance + , zi=~0, disp=~1
m_full:     Blue_area_coverage + factor(Month) + (1 + Green_area_coverage | , zi=~0, disp=~1
m_full:     City) + (1 | Location.Site:City) + (1 | Mosquito_species), zi=~0, disp=~1
              Df   AIC   BIC logLik deviance  Chisq Chi Df Pr(>Chisq)
m_wo_host_pre 27 18214 18369  -9080    18160                         
m_full        28 18216 18377  -9080    18160 0.0095      1     0.9222

Removing the Host_abundance:Predator_abundance interaction does not significantly worsen model fit, then the interaction is not needed. We move on to the next interaction.

m_wo_temp_hum <- glmmTMB(
  Mosquito_abundance ~ Green_area_coverage * Trap_type +
                       Temperature + Relative_humidity +
                       Host_abundance + Predator_abundance +
                       Blue_area_coverage +
                       factor(Month) +
                       (1 + Green_area_coverage | City) +          # City random intercept + slope
                      (1 | Location.Site:City) +        
                      (1 | Mosquito_species),
  family = nbinom2(),
  data = df,
  REML = FALSE  # ML for fixed effects comparison
)

summary(m_wo_temp_hum)
 Family: nbinom2  ( log )
Formula:          Mosquito_abundance ~ Green_area_coverage * Trap_type + Temperature +  
    Relative_humidity + Host_abundance + Predator_abundance +  
    Blue_area_coverage + factor(Month) + (1 + Green_area_coverage |  
    City) + (1 | Location.Site:City) + (1 | Mosquito_species)
Data: df

      AIC       BIC    logLik -2*log(L)  df.resid 
  18215.2   18364.3   -9081.6   18163.2      2262 

Random effects:

Conditional model:
 Groups             Name                Variance  Std.Dev. Corr  
 City               (Intercept)         6.149e-02 0.247970       
                    Green_area_coverage 3.759e-05 0.006131 -0.38 
 Location.Site:City (Intercept)         8.909e-02 0.298473       
 Mosquito_species   (Intercept)         4.585e-02 0.214137       
Number of obs: 2288, groups:  City, 6; Location.Site:City, 54; Mosquito_species, 5

Dispersion parameter for nbinom2 family ():    2 

Conditional model:
                                         Estimate Std. Error z value Pr(>|z|)    
(Intercept)                            -0.9280810  0.3606140  -2.574 0.010064 *  
Green_area_coverage                     0.0071653  0.0032923   2.176 0.029527 *  
Trap_typeLight_CO2                      0.1242485  0.0727127   1.709 0.087496 .  
Temperature                             0.0113019  0.0082549   1.369 0.170962    
Relative_humidity                       0.0211927  0.0031634   6.699 2.09e-11 ***
Host_abundance                          0.0212425  0.0021284   9.981  < 2e-16 ***
Predator_abundance                      0.0031070  0.0017451   1.780 0.075007 .  
Blue_area_coverage                      0.0074403  0.0035686   2.085 0.037073 *  
factor(Month)2                         -0.0599509  0.0838062  -0.715 0.474392    
factor(Month)3                          0.0958339  0.0921129   1.040 0.298156    
factor(Month)4                          0.1601716  0.1060906   1.510 0.131104    
factor(Month)5                          0.3753467  0.1198993   3.131 0.001745 ** 
factor(Month)6                          0.2967466  0.1303588   2.276 0.022823 *  
factor(Month)7                          0.4141824  0.1212072   3.417 0.000633 ***
factor(Month)8                          0.1090555  0.1055911   1.033 0.301693    
factor(Month)9                          0.1453758  0.0903559   1.609 0.107633    
factor(Month)10                         0.0820182  0.0818185   1.002 0.316131    
factor(Month)11                         0.0004793  0.0790249   0.006 0.995160    
factor(Month)12                        -0.0005138  0.0814086  -0.006 0.994964    
Green_area_coverage:Trap_typeLight_CO2  0.0057447  0.0012610   4.556 5.22e-06 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
anova(m_wo_host_pre, m_wo_temp_hum)
Data: df
Models:
m_wo_temp_hum: Mosquito_abundance ~ Green_area_coverage * Trap_type + Temperature + , zi=~0, disp=~1
m_wo_temp_hum:     Relative_humidity + Host_abundance + Predator_abundance + , zi=~0, disp=~1
m_wo_temp_hum:     Blue_area_coverage + factor(Month) + (1 + Green_area_coverage | , zi=~0, disp=~1
m_wo_temp_hum:     City) + (1 | Location.Site:City) + (1 | Mosquito_species), zi=~0, disp=~1
m_wo_host_pre: Mosquito_abundance ~ Green_area_coverage * Trap_type + Temperature * , zi=~0, disp=~1
m_wo_host_pre:     Relative_humidity + Host_abundance + Predator_abundance + , zi=~0, disp=~1
m_wo_host_pre:     Blue_area_coverage + factor(Month) + (1 + Green_area_coverage | , zi=~0, disp=~1
m_wo_host_pre:     City) + (1 | Location.Site:City) + (1 | Mosquito_species), zi=~0, disp=~1
              Df   AIC   BIC  logLik deviance  Chisq Chi Df Pr(>Chisq)  
m_wo_temp_hum 26 18215 18364 -9081.6    18163                           
m_wo_host_pre 27 18214 18369 -9080.0    18160 3.1134      1    0.07765 .
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Removing the Temp x Humidity interaction does not worsen model fit, the interaction should be removed. The remaining interaction is significant, therefore we move to the main effects.

m_wo_blue <- glmmTMB(
  Mosquito_abundance ~ Green_area_coverage * Trap_type +
                       Temperature + Relative_humidity +
                       Host_abundance + Predator_abundance +
                       factor(Month) +  
                       (1 + Green_area_coverage | City) +          # City random intercept + slope
                      (1 | Location.Site:City) +        
                      (1 | Mosquito_species),
  family = nbinom2(),
  data = df,
  REML = FALSE
)

summary(m_wo_blue)
 Family: nbinom2  ( log )
Formula:          Mosquito_abundance ~ Green_area_coverage * Trap_type + Temperature +  
    Relative_humidity + Host_abundance + Predator_abundance +  
    factor(Month) + (1 + Green_area_coverage | City) + (1 | Location.Site:City) +      (1 | Mosquito_species)
Data: df

      AIC       BIC    logLik -2*log(L)  df.resid 
  18217.4   18360.8   -9083.7   18167.4      2263 

Random effects:

Conditional model:
 Groups             Name                Variance  Std.Dev. Corr  
 City               (Intercept)         9.077e-02 0.30127        
                    Green_area_coverage 3.587e-05 0.00599  -0.43 
 Location.Site:City (Intercept)         9.713e-02 0.31166        
 Mosquito_species   (Intercept)         4.650e-02 0.21565        
Number of obs: 2288, groups:  City, 6; Location.Site:City, 54; Mosquito_species, 5

Dispersion parameter for nbinom2 family ():    2 

Conditional model:
                                         Estimate Std. Error z value Pr(>|z|)    
(Intercept)                            -0.7160550  0.3541022  -2.022  0.04316 *  
Green_area_coverage                     0.0074203  0.0032834   2.260  0.02382 *  
Trap_typeLight_CO2                      0.1237693  0.0726909   1.703  0.08863 .  
Temperature                             0.0112996  0.0082553   1.369  0.17107    
Relative_humidity                       0.0212518  0.0031635   6.718 1.85e-11 ***
Host_abundance                          0.0211876  0.0021288   9.953  < 2e-16 ***
Predator_abundance                      0.0030344  0.0017452   1.739  0.08208 .  
factor(Month)2                         -0.0604923  0.0838047  -0.722  0.47040    
factor(Month)3                          0.0956423  0.0921279   1.038  0.29920    
factor(Month)4                          0.1595994  0.1060774   1.505  0.13244    
factor(Month)5                          0.3750395  0.1198909   3.128  0.00176 ** 
factor(Month)6                          0.2964331  0.1303665   2.274  0.02298 *  
factor(Month)7                          0.4142905  0.1211931   3.418  0.00063 ***
factor(Month)8                          0.1085706  0.1055968   1.028  0.30387    
factor(Month)9                          0.1443938  0.0903574   1.598  0.11004    
factor(Month)10                         0.0821350  0.0818163   1.004  0.31543    
factor(Month)11                         0.0006321  0.0790305   0.008  0.99362    
factor(Month)12                        -0.0016955  0.0814145  -0.021  0.98339    
Green_area_coverage:Trap_typeLight_CO2  0.0057879  0.0012602   4.593 4.37e-06 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
anova(m_wo_temp_hum, m_wo_blue)
Data: df
Models:
m_wo_blue: Mosquito_abundance ~ Green_area_coverage * Trap_type + Temperature + , zi=~0, disp=~1
m_wo_blue:     Relative_humidity + Host_abundance + Predator_abundance + , zi=~0, disp=~1
m_wo_blue:     factor(Month) + (1 + Green_area_coverage | City) + (1 | Location.Site:City) + , zi=~0, disp=~1
m_wo_blue:     (1 | Mosquito_species), zi=~0, disp=~1
m_wo_temp_hum: Mosquito_abundance ~ Green_area_coverage * Trap_type + Temperature + , zi=~0, disp=~1
m_wo_temp_hum:     Relative_humidity + Host_abundance + Predator_abundance + , zi=~0, disp=~1
m_wo_temp_hum:     Blue_area_coverage + factor(Month) + (1 + Green_area_coverage | , zi=~0, disp=~1
m_wo_temp_hum:     City) + (1 | Location.Site:City) + (1 | Mosquito_species), zi=~0, disp=~1
              Df   AIC   BIC  logLik deviance  Chisq Chi Df Pr(>Chisq)  
m_wo_blue     25 18217 18361 -9083.7    18167                           
m_wo_temp_hum 26 18215 18364 -9081.6    18163 4.2241      1    0.03985 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Removal of blue zone coverage worsened the model, we retain it. Month shows mixed significance, so we will try removing it and compare the model fits.

m_wo_month <- glmmTMB(
  Mosquito_abundance ~ Green_area_coverage * Trap_type +
                       Temperature + Relative_humidity +
                       Host_abundance + Predator_abundance +
                       Blue_area_coverage +
                       (1 + Green_area_coverage | City) +          # City random intercept + slope
                      (1 | Location.Site:City) +        
                      (1 | Mosquito_species),
  family = nbinom2(),
  data = df,
  REML = FALSE
)

anova(m_wo_temp_hum, m_wo_month)
Data: df
Models:
m_wo_month: Mosquito_abundance ~ Green_area_coverage * Trap_type + Temperature + , zi=~0, disp=~1
m_wo_month:     Relative_humidity + Host_abundance + Predator_abundance + , zi=~0, disp=~1
m_wo_month:     Blue_area_coverage + (1 + Green_area_coverage | City) + (1 | , zi=~0, disp=~1
m_wo_month:     Location.Site:City) + (1 | Mosquito_species), zi=~0, disp=~1
m_wo_temp_hum: Mosquito_abundance ~ Green_area_coverage * Trap_type + Temperature + , zi=~0, disp=~1
m_wo_temp_hum:     Relative_humidity + Host_abundance + Predator_abundance + , zi=~0, disp=~1
m_wo_temp_hum:     Blue_area_coverage + factor(Month) + (1 + Green_area_coverage | , zi=~0, disp=~1
m_wo_temp_hum:     City) + (1 | Location.Site:City) + (1 | Mosquito_species), zi=~0, disp=~1
              Df   AIC   BIC  logLik deviance  Chisq Chi Df Pr(>Chisq)   
m_wo_month    15 18223 18309 -9096.4    18193                            
m_wo_temp_hum 26 18215 18364 -9081.6    18163 29.623     11   0.001815 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Removing the month worsens the fit, so our final model is:

m_final <- glmmTMB(
  Mosquito_abundance ~ Green_area_coverage * Trap_type +
                       Temperature + Relative_humidity +
                       Host_abundance + Predator_abundance +
                       factor(Month) +  
                       Blue_area_coverage +
                       (1 + Green_area_coverage | City) +          # City random intercept + slope
                      (1 | Location.Site:City) +        
                      (1 | Mosquito_species), 
  family = nbinom2(),
  data = df,
  REML = TRUE
)

summary(m_final)
 Family: nbinom2  ( log )
Formula:          Mosquito_abundance ~ Green_area_coverage * Trap_type + Temperature +  
    Relative_humidity + Host_abundance + Predator_abundance +  
    factor(Month) + Blue_area_coverage + (1 + Green_area_coverage |  
    City) + (1 | Location.Site:City) + (1 | Mosquito_species)
Data: df

      AIC       BIC    logLik -2*log(L)  df.resid 
  18332.7   18481.8   -9140.4   18280.7      2262 

Random effects:

Conditional model:
 Groups             Name                Variance  Std.Dev. Corr  
 City               (Intercept)         8.433e-02 0.290393       
                    Green_area_coverage 5.007e-05 0.007076 -0.47 
 Location.Site:City (Intercept)         9.124e-02 0.302060       
 Mosquito_species   (Intercept)         5.091e-02 0.225636       
Number of obs: 2288, groups:  City, 6; Location.Site:City, 54; Mosquito_species, 5

Dispersion parameter for nbinom2 family (): 1.98 

Conditional model:
                                         Estimate Std. Error z value Pr(>|z|)    
(Intercept)                            -0.9306526  0.3687708  -2.524 0.011614 *  
Green_area_coverage                     0.0070819  0.0036047   1.965 0.049460 *  
Trap_typeLight_CO2                      0.1241486  0.0729250   1.702 0.088677 .  
Temperature                             0.0116819  0.0082860   1.410 0.158586    
Relative_humidity                       0.0212013  0.0031738   6.680 2.39e-11 ***
Host_abundance                          0.0212067  0.0021355   9.930  < 2e-16 ***
Predator_abundance                      0.0030975  0.0017508   1.769 0.076866 .  
factor(Month)2                         -0.0609114  0.0840613  -0.725 0.468693    
factor(Month)3                          0.0934745  0.0924016   1.012 0.311724    
factor(Month)4                          0.1568507  0.1064307   1.474 0.140553    
factor(Month)5                          0.3708248  0.1202928   3.083 0.002051 ** 
factor(Month)6                          0.2913307  0.1308038   2.227 0.025932 *  
factor(Month)7                          0.4096605  0.1216106   3.369 0.000755 ***
factor(Month)8                          0.1055351  0.1059346   0.996 0.319139    
factor(Month)9                          0.1430460  0.0906455   1.578 0.114547    
factor(Month)10                         0.0811003  0.0820680   0.988 0.323051    
factor(Month)11                         0.0003518  0.0792615   0.004 0.996458    
factor(Month)12                        -0.0002625  0.0816592  -0.003 0.997435    
Blue_area_coverage                      0.0073499  0.0036179   2.032 0.042202 *  
Green_area_coverage:Trap_typeLight_CO2  0.0057406  0.0012649   4.538 5.67e-06 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

4. Model Diagnostics

library(DHARMa)

# Simulate residuals
sim_res <- simulateResiduals(m_final)

# Plot residual diagnostics
plot(sim_res)

testDispersion(sim_res)

    DHARMa nonparametric dispersion test via sd of residuals fitted vs. simulated

data:  simulationOutput
dispersion = 0.67548, p-value = 0.728
alternative hypothesis: two.sided

testZeroInflation(sim_res)

    DHARMa zero-inflation test via comparison to expected zeros with simulation under H0 = fitted
    model

data:  simulationOutput
ratioObsSim = 1.0195, p-value = 0.912
alternative hypothesis: two.sided

ranef(m_final)
$City
            (Intercept) Green_area_coverage
Barcelona    0.05665254       -0.0006839102
Casablanca  -0.23987633       -0.0074754880
Montpellier -0.28248408        0.0087906133
Nijmegen     0.30877301       -0.0061932812
Rabat        0.06450358        0.0013067294
Utrecht      0.09243128        0.0042553368

$`Location.Site:City`
              (Intercept)
1:Barcelona    0.07043914
1:Casablanca   0.03530279
1:Montpellier -0.14612773
1:Nijmegen     0.01928858
1:Rabat        0.17883180
1:Utrecht     -0.14043348
2:Barcelona   -0.21674606
2:Casablanca   0.22542755
2:Montpellier -0.34050646
2:Nijmegen     0.52709126
2:Rabat        0.47659812
2:Utrecht      0.01212399
3:Barcelona    0.23358215
3:Casablanca  -0.17418438
3:Montpellier -0.01351448
3:Nijmegen    -0.58369434
3:Rabat       -0.06142319
3:Utrecht      0.17008047
4:Barcelona   -0.04615371
4:Casablanca  -0.01484421
4:Montpellier  0.30291202
4:Nijmegen     0.34686847
4:Rabat       -0.62301501
4:Utrecht     -0.05344528
5:Barcelona    0.09420243
5:Casablanca  -0.42233337
5:Montpellier -0.06700641
5:Nijmegen     0.18584290
5:Rabat        0.15272034
5:Utrecht      0.20916035
6:Barcelona   -0.05731574
6:Casablanca   0.16563333
6:Montpellier  0.23113679
6:Nijmegen    -0.27094925
6:Rabat        0.02313622
6:Utrecht     -0.13363323
7:Barcelona   -0.18372403
7:Casablanca  -0.48904874
7:Montpellier -0.34834010
7:Nijmegen    -0.02084802
7:Rabat       -0.31336564
7:Utrecht     -0.01039561
8:Barcelona    0.20354565
8:Casablanca   0.21546823
8:Montpellier -0.15625847
8:Nijmegen     0.22299093
8:Rabat        0.47731495
8:Utrecht      0.13005884
9:Barcelona   -0.03759367
9:Casablanca  -0.07094313
9:Montpellier  0.37974388
9:Nijmegen    -0.16354145
9:Rabat       -0.18702398
9:Utrecht      0.05690802

$Mosquito_species
                       (Intercept)
Aedes aegypti           0.38422767
Aedes albopictus       -0.14656346
Anopheles gambiae      -0.04100560
Culex pipiens          -0.16165110
Culex quinquefasciatus -0.03500751

5. Model Interpretation

library(ggeffects)
preds <- ggpredict(m_final, terms = c("Green_area_coverage", "Trap_type"))
plot(preds) + labs(y="Predicted Mosquito Abundance")

pred_temp <- ggpredict(m_final, terms = "Temperature [all]")
plot(pred_temp) + 
  labs(title = "Predicted Mosquito Abundance", 
       y="Predicted Mosquito Abundance")


pred_host <- ggpredict(m_final, terms = "Host_abundance")
plot(pred_host) +
  labs(x="Host abundance", y="Predicted mosquitoes") +
  theme_minimal()


pred_pre <- ggpredict(m_final, terms = "Predator_abundance")
plot(pred_pre) +
  labs(x="Predator abundance", y="Predicted mosquitoes") +
  theme_minimal()


pred_month <- ggpredict(m_final, terms = "Month [1:12]")

plot(pred_month) +
  scale_x_continuous(breaks = 1:12,
                     labels = month.abb) +
  labs(x="Month", y="Predicted mosquitoes",
       title="Seasonal effect") +
  theme_minimal()

NA
NA
re_plots = sjPlot::plot_model(m_final, type = "re") 

re_plots[[1]] + theme_minimal()

re_plots[[3]] + theme_minimal()

library(sjPlot)

plot_model(m_final, type = "est", 
           axis.lim = c(0.8, 1.4),        
           show.values = TRUE,             
           value.offset = 0.3,            
           value.size = 2.5,               
           dot.size = 2,                
           line.size = 0.7,
           vline.color = 'black') +              
  labs(title = "Incidence Rate Ratios (IRR)",
       x = "Incidence Rate Ratio") +
  theme_minimal()     

icc_values <- performance::icc(m_final, tolerance = 1e-6)
icc_values
# Intraclass Correlation Coefficient

    Adjusted ICC: 0.399
  Unadjusted ICC: 0.261

5. Visualizations


ggplot(df, aes(x = factor(Green_level), y = Mosquito_abundance, fill = Trap_type)) +
  geom_boxplot(alpha = 0.7, outlier.size = 0.5) +
  theme_minimal(base_size = 14) +
  labs(
    title = "Observed Mosquito Count by Greenness Level and Trap Type",
    x = "Urban Greenness Level",
    y = "Observed Mosquito Abundance"
  ) +
  scale_fill_brewer(palette = "Set2")

Mosquito abundance increases consistently with greenness level across both trap types. Although Light–CO₂ traps and Human–Odor–CO₂ traps show similar distributions, greener areas clearly host higher mosquito numbers. This provides initial, descriptive evidence of an ecological gradient before modeling.

num_df <- df %>% select(Temperature_2m, Relative_humidity, Blue_area_coverage, Green_area_coverage = Green_level)
corrplot(cor(num_df), method = "color", type = "upper", tl.col = "black")

df$Green_level <- as.factor(df$Green_level)

# Refit model
model_abundance2 <- glmmTMB(
  Mosquito_abundance ~ Green_level * Trap_type + Temperature_2m +
    Relative_humidity + Blue_area_coverage +
    (1 | Location.Site) + (1 | Mosquito_species),
  family = nbinom2(),
  data = df
)

# Estimated marginal means
emm <- emmeans(model_abundance2, ~ Green_level * Trap_type, type = "response")

# Plot interaction
plot(emm, comparison = TRUE) +
  labs(
    title = "Predicted Mosquito Abundance by Green Level and Trap Type",
    x = "Urban Greenness Level",
    y = "Predicted Abundance (Response Scale)"
  )

The model predicts a strong increase in mosquito abundance with higher urban greenness, indicating vegetation-rich environments favor mosquito populations. The effect of trap type is minimal — both traps capture similar numbers of mosquitoes across all vegetation levels. Confidence intervals widen at higher greenness levels, suggesting greater variability in mosquito counts in green zones.



# Extract random effects and standard deviations
ran_list <- ranef(model_abundance)$cond

# Convert to a tidy data frame
ran_df <- bind_rows(
  lapply(names(ran_list), function(g) {
    data.frame(
      Group = g,
      Level = rownames(ran_list[[g]]),
      Estimate = ran_list[[g]][, "(Intercept)"]
    )
  })
)

# Plot
ggplot(ran_df, aes(x = reorder(Level, Estimate), y = Estimate, color = Group)) +
  geom_point(size = 2) +
  coord_flip() +
  facet_wrap(~ Group, scales = "free_y") +
  theme_minimal(base_size = 13) +
  labs(
    title = "Random Effects by Site and Species",
    x = "Level (Site / Species)",
    y = "Deviation from Average Abundance"
  ) +
  theme(legend.position = "none",
        axis.text.y = element_text(angle = 15, vjust = 0.5),)

Weather data visualitaon

ggplot(df, aes(x = Temperature_2m)) +
  geom_histogram(binwidth = 1, fill = "steelblue", color = "white", alpha = 0.8) +
  labs(
    title = "Temperature Distribution Across Sampling Sites",
    x = "Temperature (°C)",
    y = "Frequency"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16),
    axis.text.x = element_text(angle = 45, hjust = 1)
  )
ggplot(df, aes(x = City, y = Relative_humidity, fill = City)) +
  geom_boxplot(alpha = 0.7) +
  labs(
    title = "Variation in Relative Humidity by City",
    x = "City",
    y = "Relative Humidity (%)"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16),
    legend.position = "none",
    axis.text.x = element_text(angle = 45, hjust = 1)
  )
df %>%
  ggplot(aes(x = Wind_speed_10m, fill = City)) +
  geom_density(alpha = 0.5) +
  labs(
    title = "Distribution of Wind Speed Across Cities",
    x = "Wind Speed (m/s)",
    y = "Density",
    fill = "City"
  ) +
  theme_minimal(base_size = 14)

df %>%
  mutate(Month = month(Sampling_date, label = TRUE, abbr = TRUE)) %>%
  group_by(City, Month) %>%
  summarise(Mean_Temperature = mean(Temperature_2m, na.rm = TRUE)) %>%
  ggplot(aes(x = Month, y = Mean_Temperature, color = City, group = City)) +
  geom_line(size = 1.2) +
  geom_point(size = 2) +
  labs(
    title = "Average Monthly Temperature by City",
    x = "Month",
    y = "Temperature (°C)",
    color = "City"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    plot.title = element_text(face = "bold", size = 16)
  )

pred_inter <- ggpredict(
  model_abundance,
  terms = c("Green_level", "Trap_type"),
  type = "fixed",              # correct for your version
  bias_correction = TRUE
)

pred_df <- as.data.frame(pred_inter)


ggplot(pred_df, aes(
  x = factor(x),       # Greenness levels
  y = group,           # Trap types
  fill = predicted
)) +
  geom_tile(color = "white") +
  geom_text(aes(label = round(predicted, 1)), color = "black", size = 4) +
  scale_fill_gradient(low = "#fefefe", high = "#01665e") +
  labs(
    title = "Predicted Mosquito Count by Greenness Level and Trap Type",
    x = "Urban Greenness Level",
    y = "Trap Type",
    fill = "Predicted\nAbundance"
  ) +
  theme_minimal(base_size = 14)+
  theme(plot.title = element_text(size=12))

Mosquito abundance rises markedly with increasing urban greenness, regardless of the trap type used. The model predicts roughly five times more mosquitoes in highly vegetated areas than in low-greenness zones, highlighting the ecological importance of vegetation in mosquito distribution.

df_pred <- df %>%
  mutate(
    Predicted = predict(model_abundance, type = "response"),
    Observed = Mosquito_abundance
  )


ggplot(df_pred, aes(x = Predicted, y = Observed)) +
  geom_point(alpha = 0.4, size = 2) +
  geom_smooth(method = "lm", color = "#01665e", se = TRUE) +
  labs(
    title = "Model Fit: Predicted vs Observed Mosquito Abundance",
    x = "Predicted Abundance (Model)",
    y = "Observed Abundance (Data)"
  ) +
  theme_minimal(base_size = 14)
df %>%
  group_by(Green_level, Mosquito_species) %>%
  summarise(Mean_abundance = mean(Mosquito_abundance)) %>%
  ggplot(aes(x = factor(Green_level), y = Mean_abundance, fill = Mosquito_species)) +
  geom_bar(stat = "identity", position = "fill") +
  labs(
    title = "Relative Mosquito Species Composition by Greenness Level",
    x = "Urban Greenness Level",
    y = "Proportion of Total Abundance"
  ) +
  theme_minimal(base_size = 14)

df %>%
  mutate(Month = month(Sampling_date, label = TRUE, abbr = TRUE)) %>%
  group_by(Month) %>%
  summarise(Mean_abundance = mean(Mosquito_abundance)) %>%
  ggplot(aes(x = Month, y = Mean_abundance, group = 1)) +
  geom_line(size = 1.2, color = "#01665e") +
  geom_point(size = 2, color = "#01665e") +
  labs(
    title = "Seasonal Trend in Mosquito Abundance",
    x = "Month",
    y = "Average Abundance"
  ) +
  theme_minimal(base_size = 14)
df %>%
  mutate(Month = month(Sampling_date, label = TRUE, abbr = TRUE)) %>%
  group_by(City, Month) %>%
  summarise(Mean_abundance = mean(Mosquito_abundance, na.rm = TRUE)) %>%
  ggplot(aes(x = Month, y = Mean_abundance, group = 1)) +
  geom_line(color = "#01665e", size = 1.2) +
  geom_point(color = "#01665e", size = 2) +
  facet_wrap(~ City, ncol = 2) +
  labs(
    title = "Seasonal Trends in Mosquito Abundance by City",
    x = "Month",
    y = "Average Mosquito Abundance"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16),
    strip.text = element_text(size = 12),
    axis.text.x = element_text(angle = 90, vjust = 0.5)
  )
df %>%
  mutate(Month = month(Sampling_date, label = TRUE, abbr = TRUE)) %>%
  group_by(City, Month) %>%
  summarise(Mean_abundance = mean(Mosquito_abundance, na.rm = TRUE)) %>%
  ggplot(aes(x = Month, y = Mean_abundance, color = City, group = City)) +
  geom_line(size = 1.2) +
  geom_point(size = 2) +
  labs(
    title = "Seasonal Trends in Mosquito Abundance by City",
    x = "Month",
    y = "Average Mosquito Abundance",
    color = "City"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16),
    legend.position = "bottom"
  )
df %>%
  mutate(Month = month(Sampling_date, label = TRUE, abbr = TRUE)) %>%
  group_by(Mosquito_species, Month) %>%
  summarise(Mean_abundance = mean(Mosquito_abundance, na.rm = TRUE), .groups = "drop") %>%
  ggplot(aes(x = Month, y = Mean_abundance, color = Mosquito_species, group = Mosquito_species)) +
  geom_point(size = 2) +
  geom_smooth(se = FALSE, linewidth = 1.2, method = "loess") +
  labs(
    title = "Seasonal Trends in Mosquito Abundance by Species",
    x = "Month",
    y = "Average Mosquito Abundance",
    color = "Species"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16),
    legend.position = "bottom"
  )

df$Date <- as.Date(df$Sampling_date, format = "%Y-%m-%d")

# Create the monthly trend plot
df %>%
  mutate(Month = month(Date, label = TRUE, abbr = TRUE)) %>%
  group_by(Mosquito_species, Month) %>%
  summarise(Mean_abundance = mean(Mosquito_abundance, na.rm = TRUE), .groups = "drop") %>%
  ggplot(aes(x = Month, y = Mean_abundance, color = Mosquito_species, group = Mosquito_species)) +
  geom_line(linewidth = 1.2) +
  geom_point(size = 2) +
  labs(
    title = "Monthly Trends in Mosquito Abundance by Species",
    x = "Month",
    y = "Average Mosquito Abundance",
    color = "Species"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16),
    legend.position = "bottom"
  )

# Create faceted plot by species
df %>%
  mutate(Month = month(Date, label = TRUE, abbr = TRUE)) %>%
  group_by(Mosquito_species, Month) %>%
  summarise(Mean_abundance = mean(Mosquito_abundance, na.rm = TRUE), .groups = "drop") %>%
  ggplot(aes(x = Month, y = Mean_abundance, group = 1)) +
  geom_line(color = "#2C7BB6", linewidth = 1.2) +
  geom_point(color = "#2C7BB6", size = 2) +
  facet_wrap(~ Mosquito_species, scales = "free_y") +
  labs(
    title = "Monthly Trends in Mosquito Abundance by Species",
    x = "Month",
    y = "Average Mosquito Abundance"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16, hjust = 0.5),
    strip.text = element_text(face = "bold"),
    axis.text.x = element_text(angle = 90, vjust = 0.5),
    legend.position = "none"
  )
ggplot(df, aes(x = Trap_type, y = Mosquito_abundance, fill = Trap_type)) +
  geom_boxplot(outlier.alpha = 0.2) +
  facet_wrap(~ City) +
  scale_fill_brewer(palette = "Set2") +
  labs(
    title = "Distribution of Mosquito Abundance by Trap Type and City",
    x = "Trap Type", y = "Mosquito Abundance"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    legend.position = "none",
    axis.text.x = element_text(angle = 45, hjust = 1)
  )
LS0tCnRpdGxlOiAiTW9kZWwgU3Blc2lmaWNhdGlvbnMiCmF1dGhvcjogIkF0YWthbl9Ba2d1biwgQXlsaW4gS2FyYXBhbmFyIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKCmBgYHtyfQojIEVzc2VudGlhbCBsaWJyYXJpZXMKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeShnZ2VmZmVjdHMpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShESEFSTWEpCmxpYnJhcnkoZ2xtbVRNQikKbGlicmFyeShkcGx5cikKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoZW1tZWFucykKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocGVyZm9ybWFuY2UpCmxpYnJhcnkoc2pQbG90KQpgYGAKCiMjIDEuIERhdGEgSW1wb3J0IGFuZCBQcmVwYXJhdGlvbgoKYGBge3J9CmRmIDwtIHJlYWQuY3N2KCIuL2RhdGEvTW9ja19Nb3NxdWl0b19NaXhlZEVmZmVjdHNfd19zbG9wZXNfRGF0YXNldC5jc3YiKQpkZiRUcmFwX3R5cGUgPSBmYWN0b3IoZGYkVHJhcF90eXBlKQpkZiRNb3NxdWl0b19zcGVjaWVzID0gZmFjdG9yKGRmJE1vc3F1aXRvX3NwZWNpZXMpCgpgYGAKCmBgYHtyfQpoZWFkKGRmKQpgYGAKCiMjIDIuIE1vZGVsIFNwZWNpZmljYXRpb24KCiMjIyBEZWZpbmluZyBSYW5kb20gRWZmZWN0cwoKV2Ugc3RhcnQgYnkgZmlyc3QgZGVmaW5pbmcgdGhlIHJhbmRvbSBlZmZlY3RzIHBhcnQuIFRoZXJlIGFyZSB0d28gcmFuZG9tIGVmZmVjdHMgZGVmaW5lZCBpbiBvdXIgbW9kZWwsIG9uZSBmb3IgdGhlIG5lc3RlZCBzdHJ1Y3R1cmUgaW4gb3VyIGRhdGEgYW5kIHRoZSBvdGhlciBmb3IgdGhlIG1vc3F1aXRvIHNwZWNpZXMuIEJ5IGRlZmluaW5nIHJhbmRvbSBpbnRlcmNlcHRzIGluIG0xIG1vZGVsLCB3ZSBhc3N1bWUgdGhhdCBkaWZmZXJlbnQgY2l0aWVzIGhhdmUgZGlmZmVyZW50IGJhc2VsaW5lIGFidW5kYW5jZSBsZXZlbHMsIGRpZmZlcmVudCBzaXRlcyB3aXRoaW4gdGhlIHNhbWUgY2l0eSBoYXZlIGRpZmZlcmVudCBiYXNlbGluZSBhYnVuZGFuY2UsIGFuZCBkaWZmZXJlbnQgbW9zcXVpdG8gc3BlY2llcyBoYXZlIGRpZmZlcmVudCBiYXNlbGluZSBhYnVuZGFuY2UgbGV2ZWxzLiBIb3dldmVyLCB0aGUgc2xvcGVzIHJlbWFpbiBjb25zaXN0ZW50IG1lYW5pbmcgYWxsIGNpdGllcyBhbmQgc3BlY2llcyByZXNwb25kIHRvIGdyZWVuIGNvdmVyYWdlIHRoZSBzYW1lIHdheS4KCgpgYGB7cn0KbTFfYmFzZWxpbmUgPC0gZ2xtbVRNQigKICBNb3NxdWl0b19hYnVuZGFuY2UgfiBHcmVlbl9hcmVhX2NvdmVyYWdlICogVHJhcF90eXBlICsKICAgICAgICAgICAgICAgICAgICAgICBUZW1wZXJhdHVyZSAqIFJlbGF0aXZlX2h1bWlkaXR5ICsKICAgICAgICAgICAgICAgICAgICAgICBIb3N0X2FidW5kYW5jZSAqIFByZWRhdG9yX2FidW5kYW5jZSArCiAgICAgICAgICAgICAgICAgICAgICAgQmx1ZV9hcmVhX2NvdmVyYWdlICsKICAgICAgICAgICAgICAgICAgICAgICBmYWN0b3IoTW9udGgpICsKICAgICAgICAgICAgICAgICAgICAgICAoMSB8IENpdHkgLyBMb2NhdGlvbi5TaXRlKSArICAgICAgIyBuZXN0ZWQgcmFuZG9tIGVmZmVjdHMKICAgICAgICAgICAgICAgICAgICAgICAoMSB8IE1vc3F1aXRvX3NwZWNpZXMpLCAgICAgICAgICAgIyByYW5kb20gaW50ZXJjZXB0IGJ5IHNwZWNpZXMKICBmYW1pbHkgPSBuYmlub20yKCksCiAgZGF0YSA9IGRmLAogIFJFTUwgPSBUUlVFCikKCnN1bW1hcnkobTFfYmFzZWxpbmUpCgpiYXNlbGluZV9haWMgPC0gQUlDKG0xX2Jhc2VsaW5lKQpjYXQoIkJhc2VsaW5lIEFJQzoiLCBiYXNlbGluZV9haWMsICJcbiIpCmBgYAoKSW4gdGhlIHNlY29uZCBtb2RlbCwgd2UgY29uc2lkZXIgcmFuZG9tIHNsb3BlcyBmb3IgZ3JlZW4gbGV2ZWxzIGluIHRoZSBjaXRpZXMsIG1lYW5pbmcgdGhhdCB0aGUgZWZmZWN0IG9mIHVyYmFuIGdyZWVuIGRpZmZlcnMgcGVyIGNpdHkuCgpgYGB7cn0KbTJfY2l0eV9ncmVlbiA8LSBnbG1tVE1CKAogIE1vc3F1aXRvX2FidW5kYW5jZSB+IEdyZWVuX2FyZWFfY292ZXJhZ2UgKiBUcmFwX3R5cGUgKwogICAgICAgICAgICAgICAgICAgICAgIFRlbXBlcmF0dXJlICogUmVsYXRpdmVfaHVtaWRpdHkgKwogICAgICAgICAgICAgICAgICAgICAgIEhvc3RfYWJ1bmRhbmNlICogUHJlZGF0b3JfYWJ1bmRhbmNlICsKICAgICAgICAgICAgICAgICAgICAgICBCbHVlX2FyZWFfY292ZXJhZ2UgKwogICAgICAgICAgICAgICAgICAgICAgIGZhY3RvcihNb250aCkgKwogICAgICAgICAgICAgICAgICAgICAgKDEgKyBHcmVlbl9hcmVhX2NvdmVyYWdlIHwgQ2l0eSkgKyAgICAgICAgICAjIENpdHkgcmFuZG9tIGludGVyY2VwdCArIHNsb3BlCiAgICAgICAgICAgICAgICAgICAgICAoMSB8IExvY2F0aW9uLlNpdGU6Q2l0eSkgKyAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAoMSB8IE1vc3F1aXRvX3NwZWNpZXMpLAogIGZhbWlseSA9IG5iaW5vbTIoKSwKICBkYXRhID0gZGYsCiAgUkVNTCA9VFJVRQopCgoKIyBDaGVjayBjb252ZXJnZW5jZQpjaGVja19jb252ZXJnZW5jZShtMl9jaXR5X2dyZWVuKQptMl9jaXR5X2dyZWVuJHNkciRwZEhlc3MKCmNhdCgiQUlDIGRpZmZlcmVuY2U6IiwgQUlDKG0yX2NpdHlfZ3JlZW4pIC0gYmFzZWxpbmVfYWljLCAiXG4iKQoKbHJ0X20yIDwtIGFub3ZhKG0xX2Jhc2VsaW5lLCBtMl9jaXR5X2dyZWVuKSRDaGlzcVsyXQoKcF9tMiA8LSAwLjUgKiBwY2hpc3EobHJ0X20yLCBkZiA9IDIsIGxvd2VyLnRhaWwgPSBGQUxTRSkgKyAKICAgICAgICAgICAwLjUgKiBwY2hpc3EobHJ0X20yLCBkZiA9IDEsIGxvd2VyLnRhaWwgPSBGQUxTRSkKY2F0KCJwLXZhbHVlOiIsIHBfbTIsICJcbiIpCgpgYGAKCkFJQyBkaWZmZXJlbmNlIGlzIG5lZ2F0aXZlIGFuZCB0aGUgJEhfMDogXHRleHR7Q2l0aWVzIGRvIG5vdCBkaWZmZXIgaW4gaG93IHVyYmFuIGdyZWVuIGxldmVsIGFmZmVjdHMgbW9zcXVpdG8gYWJ1bmRhbmNlfSQgaXMgcmVqZWN0ZWQgKHA8MC4wNSksIHRoZSByYW5kb20gc2xvcGUgb2YgdXJiYW4gZ3JlZW4gbGV2ZWwgaXMgc2lnbmlmaWNhbnQuCgoKYGBge3J9Cm0zX2NpdHlfdGVtcCA8LSBnbG1tVE1CKAogIE1vc3F1aXRvX2FidW5kYW5jZSB+IEdyZWVuX2FyZWFfY292ZXJhZ2UgKiBUcmFwX3R5cGUgKwogICAgICAgICAgICAgICAgICAgICAgIFRlbXBlcmF0dXJlICogUmVsYXRpdmVfaHVtaWRpdHkgKwogICAgICAgICAgICAgICAgICAgICAgIEhvc3RfYWJ1bmRhbmNlICogUHJlZGF0b3JfYWJ1bmRhbmNlICsKICAgICAgICAgICAgICAgICAgICAgICBCbHVlX2FyZWFfY292ZXJhZ2UgKwogICAgICAgICAgICAgICAgICAgICAgIGZhY3RvcihNb250aCkgKwogICAgICAgICAgICAgICAgICAgICAgKDEgKyBUZW1wZXJhdHVyZSB8IENpdHkpICsgICAgICAKICAgICAgICAgICAgICAgICAgICAgICgxIHwgTG9jYXRpb24uU2l0ZTpDaXR5KSArICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICgxIHwgTW9zcXVpdG9fc3BlY2llcyksCiAgZmFtaWx5ID0gbmJpbm9tMigpLAogIGRhdGEgPSBkZiwKICBSRU1MID0gVFJVRQopCgojIENoZWNrIGNvbnZlcmdlbmNlCmNoZWNrX2NvbnZlcmdlbmNlKG0zX2NpdHlfdGVtcCkKbTNfY2l0eV90ZW1wJHNkciRwZEhlc3MKCmNhdCgiQUlDIGRpZmZlcmVuY2U6IiwgQUlDKG0zX2NpdHlfdGVtcCkgLSBiYXNlbGluZV9haWMsICJcbiIpCgpscnRfbTMgPC0gYW5vdmEobTFfYmFzZWxpbmUsIG0zX2NpdHlfdGVtcCkkQ2hpc3FbMl0KCnBfbTMgPC0gMC41ICogcGNoaXNxKGxydF9tMywgZGYgPSAyLCBsb3dlci50YWlsID0gRkFMU0UpICsKICAgICAgICAwLjUgKiBwY2hpc3EobHJ0X20zLCBkZiA9IDEsIGxvd2VyLnRhaWwgPSBGQUxTRSkKY2F0KCJwLXZhbHVlIGZvciBUZW1wIHNsb3BlOiIsIHBfbTMsICJcbiIpCmBgYApBSUMgZGlmZmVyZW5jZSBpcyBwb3NpdGl2ZSBhbmQgdGhlICRIXzA6IFx0ZXh0e0NpdGllcyBkbyBub3QgZGlmZmVyIGluIGhvdyB0ZW1wZXJhdHVyZSBhZmZlY3RzIG1vc3F1aXRvIGFidW5kYW5jZX0kIGlzIHJldGFpbmVkIChwPjAuMDUpLCB0aGUgcmFuZG9tIHNsb3BlIG9mIHRlbXBlcmF0dXJlIGlzIG5vdCBzaWduaWZpY2FudC4KCmBgYHtyfQptNF9ib3RoX3Nsb3BlcyA8LSBnbG1tVE1CKAogIE1vc3F1aXRvX2FidW5kYW5jZSB+IEdyZWVuX2FyZWFfY292ZXJhZ2UgKiBUcmFwX3R5cGUgKwogICAgICAgICAgICAgICAgICAgICAgIFRlbXBlcmF0dXJlICogUmVsYXRpdmVfaHVtaWRpdHkgKwogICAgICAgICAgICAgICAgICAgICAgIEhvc3RfYWJ1bmRhbmNlICogUHJlZGF0b3JfYWJ1bmRhbmNlICsKICAgICAgICAgICAgICAgICAgICAgICBCbHVlX2FyZWFfY292ZXJhZ2UgKwogICAgICAgICAgICAgICAgICAgICAgIGZhY3RvcihNb250aCkgKwogICAgICAgICAgICAgICAgICAgICAgICgxICsgR3JlZW5fYXJlYV9jb3ZlcmFnZSArIFRlbXBlcmF0dXJlIHwgQ2l0eSkgKwogICAgICAgICAgICAgICAgICAgICAgICgxIHwgTG9jYXRpb24uU2l0ZTpDaXR5KSArCiAgICAgICAgICAgICAgICAgICAgICAgKDEgfCBNb3NxdWl0b19zcGVjaWVzKSwKICBmYW1pbHkgPSBuYmlub20yKCksCiAgZGF0YSA9IGRmLAogIFJFTUwgPSBUUlVFCikKCiMgQ2hlY2sgY29udmVyZ2VuY2UKY2hlY2tfY29udmVyZ2VuY2UobTRfYm90aF9zbG9wZXMpCm00X2JvdGhfc2xvcGVzJHNkciRwZEhlc3MKCiMgQ29tcGFyZSBtMiAtPiBtNCAoZG9lcyBhZGRpbmcgdGVtcGVyYXR1cmUgc2xvcGUgdG8gbTIgaW1wcm92ZSBmaXQ/KQpscnRfbTJfbTQgPC0gYW5vdmEobTJfY2l0eV9ncmVlbiwgbTRfYm90aF9zbG9wZXMpJENoaXNxWzJdCmNhdCgiTFJUIHN0YXQgKG0yIC0+IG00KToiLCBscnRfbTJfbTQsICJcbiIpCnBfbTJfbTQgPC0gMC41ICogcGNoaXNxKGxydF9tMl9tNCwgZGYgPSAyLCBsb3dlci50YWlsID0gRkFMU0UpICsgCiAgICAgICAgICAgMC41ICogcGNoaXNxKGxydF9tMl9tNCwgZGYgPSAxLCBsb3dlci50YWlsID0gRkFMU0UpCmNhdCgicC12YWx1ZSAobTIgLT4gbTQpOiIsIHBfbTJfbTQsICJcbiIpCgojIENvbXBhcmUgbTMgLT4gbTQgKGRvZXMgYWRkaW5nIEdyZWVuIHNsb3BlIHRvIG0zIGltcHJvdmUgZml0PykKbHJ0X20zX200IDwtIGFub3ZhKG0zX2NpdHlfdGVtcCwgbTRfYm90aF9zbG9wZXMpJENoaXNxWzJdCmNhdCgiTFJUIHN0YXQgKG0zIC0+IG00KToiLCBscnRfbTNfbTQsICJcbiIpCnBfbTNfbTQgPC0gMC41ICogcGNoaXNxKGxydF9tM19tNCwgZGYgPSAyLCBsb3dlci50YWlsID0gRkFMU0UpICsgCiAgICAgICAgICAgMC41ICogcGNoaXNxKGxydF9tM19tNCwgZGYgPSAxLCBsb3dlci50YWlsID0gRkFMU0UpCmNhdCgicC12YWx1ZSAobTMgLT4gbTQpOiIsIHBfbTNfbTQsICJcbiIpCgojIENvbXBhcmUgYWxsIG1vZGVscyBieSBBSUMgCm1vZGVscyA8LSBsaXN0KG0xX2Jhc2VsaW5lID0gbTFfYmFzZWxpbmUsIG0yID0gbTJfY2l0eV9ncmVlbiwgbTMgPSBtM19jaXR5X3RlbXAsIG00ID0gbTRfYm90aF9zbG9wZXMpCmFpY190YWIgPC0gZGF0YS5mcmFtZSgKICBtb2RlbCA9IG5hbWVzKG1vZGVscyksCiAgQUlDID0gc2FwcGx5KG1vZGVscywgQUlDKSwKICBwZEhlc3MgPSBzYXBwbHkobW9kZWxzLCBmdW5jdGlvbihtKSB7IGlmIChpcy5udWxsKG0kc2RyKSkgTkEgZWxzZSBtJHNkciRwZEhlc3MgfSkKKQphaWNfdGFiIDwtIGFpY190YWIgJT4lIGFycmFuZ2UoQUlDKQpwcmludChhaWNfdGFiKQpgYGAKCkFjcm9zcyB0aGUgbW9kZWxzIHRlc3RlZCwgdGhlIGxvd2VzdCBBSUMgdmFsdWUgd2FzIHRlc3RlZCB3YXMgYWNoaWV2ZWQgYnkgbW9kZWwgMiwgZm9yIHRoZSByZW1haW5kZXIgb2YgdGhlIG1vZGVsIHNlbGVjdGlvbiBwcm9jZWR1cmUgd2Ugd2lsbCB1c2UgdGhlIHJhbmRvbSBlZmZlY3RzIGRlZmluZWQgaW4gbW9kZWwgMi4gTm93LCB3ZSB3aWxsIGZvY3VzIG9uIGdldHRpbmcgYSBtb3JlIHBhcnNpbW9uaW91cyBmaXhlZCBlZmZlY3RzIHBhcnQgYnkgcmVtb3ZpbmcgaW50ZXJhY3Rpb24gdGVybXMgaW4gYSBzdGVwIHdpc2UgbWFubmVyLgoKCmBgYHtyfQptX2Z1bGwgPC0gZ2xtbVRNQigKICBNb3NxdWl0b19hYnVuZGFuY2UgfiBHcmVlbl9hcmVhX2NvdmVyYWdlICogVHJhcF90eXBlICsKICAgICAgICAgICAgICAgICAgICAgICBUZW1wZXJhdHVyZSAqIFJlbGF0aXZlX2h1bWlkaXR5ICsKICAgICAgICAgICAgICAgICAgICAgICBIb3N0X2FidW5kYW5jZSAqIFByZWRhdG9yX2FidW5kYW5jZSArCiAgICAgICAgICAgICAgICAgICAgICAgQmx1ZV9hcmVhX2NvdmVyYWdlICsKICAgICAgICAgICAgICAgICAgICAgICBmYWN0b3IoTW9udGgpICsKICAgICAgICAgICAgICAgICAgICAgICAoMSArIEdyZWVuX2FyZWFfY292ZXJhZ2UgfCBDaXR5KSArICAgICAgICAgICMgQ2l0eSByYW5kb20gaW50ZXJjZXB0ICsgc2xvcGUKICAgICAgICAgICAgICAgICAgICAgICgxIHwgTG9jYXRpb24uU2l0ZTpDaXR5KSArICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICgxIHwgTW9zcXVpdG9fc3BlY2llcyksCiAgZmFtaWx5ID0gbmJpbm9tMigpLAogIGRhdGEgPSBkZiwKICBSRU1MID0gRkFMU0UgICMgTUwgZm9yIGZpeGVkIGVmZmVjdHMgY29tcGFyaXNvbgopCgpzdW1tYXJ5KG1fZnVsbCkKYGBgCgpXZSBzdGFydCBieSByZW1vdmluZyB0aGUgbGVhc3Qgc2lnbmlmaWNhbnQgaW50ZXJhY3Rpb24gdGVybSB3aGljaCBpcyBIb3N0X2FidW5kYW5jZTpQcmVkYXRvcl9hYnVuZGFuY2UgLiAKYGBge3J9Cm1fd29faG9zdF9wcmUgPC0gZ2xtbVRNQigKICBNb3NxdWl0b19hYnVuZGFuY2UgfiBHcmVlbl9hcmVhX2NvdmVyYWdlICogVHJhcF90eXBlICsKICAgICAgICAgICAgICAgICAgICAgICBUZW1wZXJhdHVyZSAqIFJlbGF0aXZlX2h1bWlkaXR5ICsKICAgICAgICAgICAgICAgICAgICAgICBIb3N0X2FidW5kYW5jZSArIFByZWRhdG9yX2FidW5kYW5jZSArCiAgICAgICAgICAgICAgICAgICAgICAgQmx1ZV9hcmVhX2NvdmVyYWdlICsKICAgICAgICAgICAgICAgICAgICAgICBmYWN0b3IoTW9udGgpICsKICAgICAgICAgICAgICAgICAgICAgICAoMSArIEdyZWVuX2FyZWFfY292ZXJhZ2UgfCBDaXR5KSArICAgICAgICAgICMgQ2l0eSByYW5kb20gaW50ZXJjZXB0ICsgc2xvcGUKICAgICAgICAgICAgICAgICAgICAgICgxIHwgTG9jYXRpb24uU2l0ZTpDaXR5KSArICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICgxIHwgTW9zcXVpdG9fc3BlY2llcyksCiAgZmFtaWx5ID0gbmJpbm9tMigpLAogIGRhdGEgPSBkZiwKICBSRU1MID0gRkFMU0UgICMgTUwgZm9yIGZpeGVkIGVmZmVjdHMgY29tcGFyaXNvbgopCgpzdW1tYXJ5KG1fd29faG9zdF9wcmUpCmFub3ZhKG1fZnVsbCwgbV93b19ob3N0X3ByZSkKYGBgClJlbW92aW5nIHRoZSBIb3N0X2FidW5kYW5jZTpQcmVkYXRvcl9hYnVuZGFuY2UgaW50ZXJhY3Rpb24gZG9lcyBub3Qgc2lnbmlmaWNhbnRseSB3b3JzZW4gbW9kZWwgZml0LCB0aGVuIHRoZSBpbnRlcmFjdGlvbiBpcyBub3QgbmVlZGVkLiBXZSBtb3ZlIG9uIHRvIHRoZSBuZXh0IGludGVyYWN0aW9uLgoKYGBge3J9Cm1fd29fdGVtcF9odW0gPC0gZ2xtbVRNQigKICBNb3NxdWl0b19hYnVuZGFuY2UgfiBHcmVlbl9hcmVhX2NvdmVyYWdlICogVHJhcF90eXBlICsKICAgICAgICAgICAgICAgICAgICAgICBUZW1wZXJhdHVyZSArIFJlbGF0aXZlX2h1bWlkaXR5ICsKICAgICAgICAgICAgICAgICAgICAgICBIb3N0X2FidW5kYW5jZSArIFByZWRhdG9yX2FidW5kYW5jZSArCiAgICAgICAgICAgICAgICAgICAgICAgQmx1ZV9hcmVhX2NvdmVyYWdlICsKICAgICAgICAgICAgICAgICAgICAgICBmYWN0b3IoTW9udGgpICsKICAgICAgICAgICAgICAgICAgICAgICAoMSArIEdyZWVuX2FyZWFfY292ZXJhZ2UgfCBDaXR5KSArICAgICAgICAgICMgQ2l0eSByYW5kb20gaW50ZXJjZXB0ICsgc2xvcGUKICAgICAgICAgICAgICAgICAgICAgICgxIHwgTG9jYXRpb24uU2l0ZTpDaXR5KSArICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICgxIHwgTW9zcXVpdG9fc3BlY2llcyksCiAgZmFtaWx5ID0gbmJpbm9tMigpLAogIGRhdGEgPSBkZiwKICBSRU1MID0gRkFMU0UgICMgTUwgZm9yIGZpeGVkIGVmZmVjdHMgY29tcGFyaXNvbgopCgpzdW1tYXJ5KG1fd29fdGVtcF9odW0pCmFub3ZhKG1fd29faG9zdF9wcmUsIG1fd29fdGVtcF9odW0pCmBgYApSZW1vdmluZyB0aGUgVGVtcCB4IEh1bWlkaXR5IGludGVyYWN0aW9uIGRvZXMgbm90IHdvcnNlbiBtb2RlbCBmaXQsIHRoZSBpbnRlcmFjdGlvbiBzaG91bGQgYmUgcmVtb3ZlZC4gVGhlIHJlbWFpbmluZyBpbnRlcmFjdGlvbiBpcyBzaWduaWZpY2FudCwgdGhlcmVmb3JlIHdlIG1vdmUgdG8gdGhlIG1haW4gZWZmZWN0cy4KCmBgYHtyfQptX3dvX2JsdWUgPC0gZ2xtbVRNQigKICBNb3NxdWl0b19hYnVuZGFuY2UgfiBHcmVlbl9hcmVhX2NvdmVyYWdlICogVHJhcF90eXBlICsKICAgICAgICAgICAgICAgICAgICAgICBUZW1wZXJhdHVyZSArIFJlbGF0aXZlX2h1bWlkaXR5ICsKICAgICAgICAgICAgICAgICAgICAgICBIb3N0X2FidW5kYW5jZSArIFByZWRhdG9yX2FidW5kYW5jZSArCiAgICAgICAgICAgICAgICAgICAgICAgZmFjdG9yKE1vbnRoKSArICAKICAgICAgICAgICAgICAgICAgICAgICAoMSArIEdyZWVuX2FyZWFfY292ZXJhZ2UgfCBDaXR5KSArICAgICAgICAgICMgQ2l0eSByYW5kb20gaW50ZXJjZXB0ICsgc2xvcGUKICAgICAgICAgICAgICAgICAgICAgICgxIHwgTG9jYXRpb24uU2l0ZTpDaXR5KSArICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICgxIHwgTW9zcXVpdG9fc3BlY2llcyksCiAgZmFtaWx5ID0gbmJpbm9tMigpLAogIGRhdGEgPSBkZiwKICBSRU1MID0gRkFMU0UKKQoKc3VtbWFyeShtX3dvX2JsdWUpCmFub3ZhKG1fd29fdGVtcF9odW0sIG1fd29fYmx1ZSkKYGBgClJlbW92YWwgb2YgYmx1ZSB6b25lIGNvdmVyYWdlIHdvcnNlbmVkIHRoZSBtb2RlbCwgd2UgcmV0YWluIGl0LiBNb250aCBzaG93cyBtaXhlZCBzaWduaWZpY2FuY2UsIHNvIHdlIHdpbGwgdHJ5IHJlbW92aW5nIGl0IGFuZCBjb21wYXJlIHRoZSBtb2RlbCBmaXRzLgoKYGBge3J9Cm1fd29fbW9udGggPC0gZ2xtbVRNQigKICBNb3NxdWl0b19hYnVuZGFuY2UgfiBHcmVlbl9hcmVhX2NvdmVyYWdlICogVHJhcF90eXBlICsKICAgICAgICAgICAgICAgICAgICAgICBUZW1wZXJhdHVyZSArIFJlbGF0aXZlX2h1bWlkaXR5ICsKICAgICAgICAgICAgICAgICAgICAgICBIb3N0X2FidW5kYW5jZSArIFByZWRhdG9yX2FidW5kYW5jZSArCiAgICAgICAgICAgICAgICAgICAgICAgQmx1ZV9hcmVhX2NvdmVyYWdlICsKICAgICAgICAgICAgICAgICAgICAgICAoMSArIEdyZWVuX2FyZWFfY292ZXJhZ2UgfCBDaXR5KSArICAgICAgICAgICMgQ2l0eSByYW5kb20gaW50ZXJjZXB0ICsgc2xvcGUKICAgICAgICAgICAgICAgICAgICAgICgxIHwgTG9jYXRpb24uU2l0ZTpDaXR5KSArICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICgxIHwgTW9zcXVpdG9fc3BlY2llcyksCiAgZmFtaWx5ID0gbmJpbm9tMigpLAogIGRhdGEgPSBkZiwKICBSRU1MID0gRkFMU0UKKQoKYW5vdmEobV93b190ZW1wX2h1bSwgbV93b19tb250aCkKYGBgClJlbW92aW5nIHRoZSBtb250aCB3b3JzZW5zIHRoZSBmaXQsIHNvIG91ciBmaW5hbCBtb2RlbCBpczoKCmBgYHtyfQptX2ZpbmFsIDwtIGdsbW1UTUIoCiAgTW9zcXVpdG9fYWJ1bmRhbmNlIH4gR3JlZW5fYXJlYV9jb3ZlcmFnZSAqIFRyYXBfdHlwZSArCiAgICAgICAgICAgICAgICAgICAgICAgVGVtcGVyYXR1cmUgKyBSZWxhdGl2ZV9odW1pZGl0eSArCiAgICAgICAgICAgICAgICAgICAgICAgSG9zdF9hYnVuZGFuY2UgKyBQcmVkYXRvcl9hYnVuZGFuY2UgKwogICAgICAgICAgICAgICAgICAgICAgIGZhY3RvcihNb250aCkgKyAgCiAgICAgICAgICAgICAgICAgICAgICAgQmx1ZV9hcmVhX2NvdmVyYWdlICsKICAgICAgICAgICAgICAgICAgICAgICAoMSArIEdyZWVuX2FyZWFfY292ZXJhZ2UgfCBDaXR5KSArICAgICAgICAgICMgQ2l0eSByYW5kb20gaW50ZXJjZXB0ICsgc2xvcGUKICAgICAgICAgICAgICAgICAgICAgICgxIHwgTG9jYXRpb24uU2l0ZTpDaXR5KSArICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICgxIHwgTW9zcXVpdG9fc3BlY2llcyksIAogIGZhbWlseSA9IG5iaW5vbTIoKSwKICBkYXRhID0gZGYsCiAgUkVNTCA9IFRSVUUKKQoKc3VtbWFyeShtX2ZpbmFsKQoKYGBgCgoKIyMgNC4gTW9kZWwgRGlhZ25vc3RpY3MKCmBgYHtyfQojIFNpbXVsYXRlIHJlc2lkdWFscwpzaW1fcmVzIDwtIHNpbXVsYXRlUmVzaWR1YWxzKG1fZmluYWwpCgojIFBsb3QgcmVzaWR1YWwgZGlhZ25vc3RpY3MKcGxvdChzaW1fcmVzKQoKYGBgCmBgYHtyfQp0ZXN0RGlzcGVyc2lvbihzaW1fcmVzKQpgYGAKYGBge3J9CnRlc3RaZXJvSW5mbGF0aW9uKHNpbV9yZXMpCmBgYApgYGB7cn0KcmFuZWYobV9maW5hbCkKYGBgCgoKIyMgNS4gTW9kZWwgSW50ZXJwcmV0YXRpb24KYGBge3J9CnByZWRzIDwtIGdncHJlZGljdChtX2ZpbmFsLCB0ZXJtcyA9IGMoIkdyZWVuX2FyZWFfY292ZXJhZ2UiLCAiVHJhcF90eXBlIikpCnBsb3QocHJlZHMpICsgbGFicyh5PSJQcmVkaWN0ZWQgTW9zcXVpdG8gQWJ1bmRhbmNlIikKCmBgYAoKYGBge3J9CnByZWRfdGVtcCA8LSBnZ3ByZWRpY3QobV9maW5hbCwgdGVybXMgPSAiVGVtcGVyYXR1cmUgW2FsbF0iKQpwbG90KHByZWRfdGVtcCkgKyAKICBsYWJzKHRpdGxlID0gIlByZWRpY3RlZCBNb3NxdWl0byBBYnVuZGFuY2UiLCAKICAgICAgIHk9IlByZWRpY3RlZCBNb3NxdWl0byBBYnVuZGFuY2UiKQoKcHJlZF9ob3N0IDwtIGdncHJlZGljdChtX2ZpbmFsLCB0ZXJtcyA9ICJIb3N0X2FidW5kYW5jZSIpCnBsb3QocHJlZF9ob3N0KSArCiAgbGFicyh4PSJIb3N0IGFidW5kYW5jZSIsIHk9IlByZWRpY3RlZCBtb3NxdWl0b2VzIikgKwogIHRoZW1lX21pbmltYWwoKQoKcHJlZF9wcmUgPC0gZ2dwcmVkaWN0KG1fZmluYWwsIHRlcm1zID0gIlByZWRhdG9yX2FidW5kYW5jZSIpCnBsb3QocHJlZF9wcmUpICsKICBsYWJzKHg9IlByZWRhdG9yIGFidW5kYW5jZSIsIHk9IlByZWRpY3RlZCBtb3NxdWl0b2VzIikgKwogIHRoZW1lX21pbmltYWwoKQoKcHJlZF9tb250aCA8LSBnZ3ByZWRpY3QobV9maW5hbCwgdGVybXMgPSAiTW9udGggWzE6MTJdIikKCnBsb3QocHJlZF9tb250aCkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAxOjEyLAogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBtb250aC5hYmIpICsKICBsYWJzKHg9Ik1vbnRoIiwgeT0iUHJlZGljdGVkIG1vc3F1aXRvZXMiLAogICAgICAgdGl0bGU9IlNlYXNvbmFsIGVmZmVjdCIpICsKICB0aGVtZV9taW5pbWFsKCkKCgpgYGAKCgpgYGB7cn0KcmVfcGxvdHMgPSBzalBsb3Q6OnBsb3RfbW9kZWwobV9maW5hbCwgdHlwZSA9ICJyZSIpIAoKcmVfcGxvdHNbWzFdXSArIHRoZW1lX21pbmltYWwoKQpyZV9wbG90c1tbM11dICsgdGhlbWVfbWluaW1hbCgpCmBgYAoKYGBge3J9CnBsb3RfbW9kZWwobV9maW5hbCwgdHlwZSA9ICJlc3QiLCAKICAgICAgICAgICBheGlzLmxpbSA9IGMoMC44LCAxLjQpLCAgICAgICAgCiAgICAgICAgICAgc2hvdy52YWx1ZXMgPSBUUlVFLCAgICAgICAgICAgICAKICAgICAgICAgICB2YWx1ZS5vZmZzZXQgPSAwLjMsICAgICAgICAgICAgCiAgICAgICAgICAgdmFsdWUuc2l6ZSA9IDIuNSwgICAgICAgICAgICAgICAKICAgICAgICAgICBkb3Quc2l6ZSA9IDIsICAgICAgICAgICAgICAgIAogICAgICAgICAgIGxpbmUuc2l6ZSA9IDAuNywKICAgICAgICAgICB2bGluZS5jb2xvciA9ICdibGFjaycpICsgICAgICAgICAgICAgIAogIGxhYnModGl0bGUgPSAiSW5jaWRlbmNlIFJhdGUgUmF0aW9zIChJUlIpIiwKICAgICAgIHggPSAiSW5jaWRlbmNlIFJhdGUgUmF0aW8iKSArCiAgdGhlbWVfbWluaW1hbCgpICAgICAKCmBgYApgYGB7cn0KaWNjX3ZhbHVlcyA8LSBwZXJmb3JtYW5jZTo6aWNjKG1fZmluYWwsIHRvbGVyYW5jZSA9IDFlLTYpCmljY192YWx1ZXMKCmBgYAoKCiMjIDUuIFZpc3VhbGl6YXRpb25zCgpgYGB7cn0KCmdncGxvdChkZiwgYWVzKHggPSBmYWN0b3IoR3JlZW5fbGV2ZWwpLCB5ID0gTW9zcXVpdG9fYWJ1bmRhbmNlLCBmaWxsID0gVHJhcF90eXBlKSkgKwogIGdlb21fYm94cGxvdChhbHBoYSA9IDAuNywgb3V0bGllci5zaXplID0gMC41KSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJPYnNlcnZlZCBNb3NxdWl0byBDb3VudCBieSBHcmVlbm5lc3MgTGV2ZWwgYW5kIFRyYXAgVHlwZSIsCiAgICB4ID0gIlVyYmFuIEdyZWVubmVzcyBMZXZlbCIsCiAgICB5ID0gIk9ic2VydmVkIE1vc3F1aXRvIEFidW5kYW5jZSIKICApICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDIiKQoKYGBgCk1vc3F1aXRvIGFidW5kYW5jZSBpbmNyZWFzZXMgY29uc2lzdGVudGx5IHdpdGggZ3JlZW5uZXNzIGxldmVsIGFjcm9zcyBib3RoIHRyYXAgdHlwZXMuCkFsdGhvdWdoIExpZ2h04oCTQ0/igoIgdHJhcHMgYW5kIEh1bWFu4oCTT2RvcuKAk0NP4oKCIHRyYXBzIHNob3cgc2ltaWxhciBkaXN0cmlidXRpb25zLCBncmVlbmVyIGFyZWFzIGNsZWFybHkgaG9zdCBoaWdoZXIgbW9zcXVpdG8gbnVtYmVycy4KVGhpcyBwcm92aWRlcyBpbml0aWFsLCBkZXNjcmlwdGl2ZSBldmlkZW5jZSBvZiBhbiBlY29sb2dpY2FsIGdyYWRpZW50IGJlZm9yZSBtb2RlbGluZy4KCgoKYGBge3J9Cm51bV9kZiA8LSBkZiAlPiUgc2VsZWN0KFRlbXBlcmF0dXJlXzJtLCBSZWxhdGl2ZV9odW1pZGl0eSwgQmx1ZV9hcmVhX2NvdmVyYWdlLCBHcmVlbl9hcmVhX2NvdmVyYWdlID0gR3JlZW5fbGV2ZWwpCmNvcnJwbG90KGNvcihudW1fZGYpLCBtZXRob2QgPSAiY29sb3IiLCB0eXBlID0gInVwcGVyIiwgdGwuY29sID0gImJsYWNrIikKCmBgYAoKCgoKYGBge3J9CgpkZiRHcmVlbl9sZXZlbCA8LSBhcy5mYWN0b3IoZGYkR3JlZW5fbGV2ZWwpCgojIFJlZml0IG1vZGVsCm1vZGVsX2FidW5kYW5jZTIgPC0gZ2xtbVRNQigKICBNb3NxdWl0b19hYnVuZGFuY2UgfiBHcmVlbl9sZXZlbCAqIFRyYXBfdHlwZSArIFRlbXBlcmF0dXJlXzJtICsKICAgIFJlbGF0aXZlX2h1bWlkaXR5ICsgQmx1ZV9hcmVhX2NvdmVyYWdlICsKICAgICgxIHwgTG9jYXRpb24uU2l0ZSkgKyAoMSB8IE1vc3F1aXRvX3NwZWNpZXMpLAogIGZhbWlseSA9IG5iaW5vbTIoKSwKICBkYXRhID0gZGYKKQoKIyBFc3RpbWF0ZWQgbWFyZ2luYWwgbWVhbnMKZW1tIDwtIGVtbWVhbnMobW9kZWxfYWJ1bmRhbmNlMiwgfiBHcmVlbl9sZXZlbCAqIFRyYXBfdHlwZSwgdHlwZSA9ICJyZXNwb25zZSIpCgojIFBsb3QgaW50ZXJhY3Rpb24KcGxvdChlbW0sIGNvbXBhcmlzb24gPSBUUlVFKSArCiAgbGFicygKICAgIHRpdGxlID0gIlByZWRpY3RlZCBNb3NxdWl0byBBYnVuZGFuY2UgYnkgR3JlZW4gTGV2ZWwgYW5kIFRyYXAgVHlwZSIsCiAgICB4ID0gIlVyYmFuIEdyZWVubmVzcyBMZXZlbCIsCiAgICB5ID0gIlByZWRpY3RlZCBBYnVuZGFuY2UgKFJlc3BvbnNlIFNjYWxlKSIKICApCgoKCmBgYApUaGUgbW9kZWwgcHJlZGljdHMgYSBzdHJvbmcgaW5jcmVhc2UgaW4gbW9zcXVpdG8gYWJ1bmRhbmNlIHdpdGggaGlnaGVyIHVyYmFuIGdyZWVubmVzcywgaW5kaWNhdGluZyB2ZWdldGF0aW9uLXJpY2ggZW52aXJvbm1lbnRzIGZhdm9yIG1vc3F1aXRvIHBvcHVsYXRpb25zLgpUaGUgZWZmZWN0IG9mIHRyYXAgdHlwZSBpcyBtaW5pbWFsIOKAlCBib3RoIHRyYXBzIGNhcHR1cmUgc2ltaWxhciBudW1iZXJzIG9mIG1vc3F1aXRvZXMgYWNyb3NzIGFsbCB2ZWdldGF0aW9uIGxldmVscy4KQ29uZmlkZW5jZSBpbnRlcnZhbHMgd2lkZW4gYXQgaGlnaGVyIGdyZWVubmVzcyBsZXZlbHMsIHN1Z2dlc3RpbmcgZ3JlYXRlciB2YXJpYWJpbGl0eSBpbiBtb3NxdWl0byBjb3VudHMgaW4gZ3JlZW4gem9uZXMuCgoKCgoKCmBgYHtyfQoKCiMgRXh0cmFjdCByYW5kb20gZWZmZWN0cyBhbmQgc3RhbmRhcmQgZGV2aWF0aW9ucwpyYW5fbGlzdCA8LSByYW5lZihtb2RlbF9hYnVuZGFuY2UpJGNvbmQKCiMgQ29udmVydCB0byBhIHRpZHkgZGF0YSBmcmFtZQpyYW5fZGYgPC0gYmluZF9yb3dzKAogIGxhcHBseShuYW1lcyhyYW5fbGlzdCksIGZ1bmN0aW9uKGcpIHsKICAgIGRhdGEuZnJhbWUoCiAgICAgIEdyb3VwID0gZywKICAgICAgTGV2ZWwgPSByb3duYW1lcyhyYW5fbGlzdFtbZ11dKSwKICAgICAgRXN0aW1hdGUgPSByYW5fbGlzdFtbZ11dWywgIihJbnRlcmNlcHQpIl0KICAgICkKICB9KQopCgojIFBsb3QKZ2dwbG90KHJhbl9kZiwgYWVzKHggPSByZW9yZGVyKExldmVsLCBFc3RpbWF0ZSksIHkgPSBFc3RpbWF0ZSwgY29sb3IgPSBHcm91cCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAyKSArCiAgY29vcmRfZmxpcCgpICsKICBmYWNldF93cmFwKH4gR3JvdXAsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJSYW5kb20gRWZmZWN0cyBieSBTaXRlIGFuZCBTcGVjaWVzIiwKICAgIHggPSAiTGV2ZWwgKFNpdGUgLyBTcGVjaWVzKSIsCiAgICB5ID0gIkRldmlhdGlvbiBmcm9tIEF2ZXJhZ2UgQWJ1bmRhbmNlIgogICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDE1LCB2anVzdCA9IDAuNSksKQoKCmBgYAoKCgojIyMgV2VhdGhlciBkYXRhIHZpc3VhbGl0YW9uIAoKYGBge3J9CmdncGxvdChkZiwgYWVzKHggPSBUZW1wZXJhdHVyZV8ybSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEsIGZpbGwgPSAic3RlZWxibHVlIiwgY29sb3IgPSAid2hpdGUiLCBhbHBoYSA9IDAuOCkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJUZW1wZXJhdHVyZSBEaXN0cmlidXRpb24gQWNyb3NzIFNhbXBsaW5nIFNpdGVzIiwKICAgIHggPSAiVGVtcGVyYXR1cmUgKMKwQykiLAogICAgeSA9ICJGcmVxdWVuY3kiCiAgKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTYpLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKQogICkKCmBgYApgYGB7cn0KZ2dwbG90KGRmLCBhZXMoeCA9IENpdHksIHkgPSBSZWxhdGl2ZV9odW1pZGl0eSwgZmlsbCA9IENpdHkpKSArCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC43KSArCiAgbGFicygKICAgIHRpdGxlID0gIlZhcmlhdGlvbiBpbiBSZWxhdGl2ZSBIdW1pZGl0eSBieSBDaXR5IiwKICAgIHggPSAiQ2l0eSIsCiAgICB5ID0gIlJlbGF0aXZlIEh1bWlkaXR5ICglKSIKICApICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNiksCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpCiAgKQoKYGBgCgpgYGB7cn0KZGYgJT4lCiAgZ2dwbG90KGFlcyh4ID0gV2luZF9zcGVlZF8xMG0sIGZpbGwgPSBDaXR5KSkgKwogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgV2luZCBTcGVlZCBBY3Jvc3MgQ2l0aWVzIiwKICAgIHggPSAiV2luZCBTcGVlZCAobS9zKSIsCiAgICB5ID0gIkRlbnNpdHkiLAogICAgZmlsbCA9ICJDaXR5IgogICkgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpCgoKYGBgCgoKYGBge3J9CgpkZiAlPiUKICBtdXRhdGUoTW9udGggPSBtb250aChTYW1wbGluZ19kYXRlLCBsYWJlbCA9IFRSVUUsIGFiYnIgPSBUUlVFKSkgJT4lCiAgZ3JvdXBfYnkoQ2l0eSwgTW9udGgpICU+JQogIHN1bW1hcmlzZShNZWFuX1RlbXBlcmF0dXJlID0gbWVhbihUZW1wZXJhdHVyZV8ybSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gTW9udGgsIHkgPSBNZWFuX1RlbXBlcmF0dXJlLCBjb2xvciA9IENpdHksIGdyb3VwID0gQ2l0eSkpICsKICBnZW9tX2xpbmUoc2l6ZSA9IDEuMikgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiQXZlcmFnZSBNb250aGx5IFRlbXBlcmF0dXJlIGJ5IENpdHkiLAogICAgeCA9ICJNb250aCIsCiAgICB5ID0gIlRlbXBlcmF0dXJlICjCsEMpIiwKICAgIGNvbG9yID0gIkNpdHkiCiAgKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2KQogICkKCmBgYAoKCgpgYGB7cn0KCnByZWRfaW50ZXIgPC0gZ2dwcmVkaWN0KAogIG1vZGVsX2FidW5kYW5jZSwKICB0ZXJtcyA9IGMoIkdyZWVuX2xldmVsIiwgIlRyYXBfdHlwZSIpLAogIHR5cGUgPSAiZml4ZWQiLCAgICAgICAgICAgICAgIyBjb3JyZWN0IGZvciB5b3VyIHZlcnNpb24KICBiaWFzX2NvcnJlY3Rpb24gPSBUUlVFCikKCnByZWRfZGYgPC0gYXMuZGF0YS5mcmFtZShwcmVkX2ludGVyKQoKCmdncGxvdChwcmVkX2RmLCBhZXMoCiAgeCA9IGZhY3Rvcih4KSwgICAgICAgIyBHcmVlbm5lc3MgbGV2ZWxzCiAgeSA9IGdyb3VwLCAgICAgICAgICAgIyBUcmFwIHR5cGVzCiAgZmlsbCA9IHByZWRpY3RlZAopKSArCiAgZ2VvbV90aWxlKGNvbG9yID0gIndoaXRlIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChwcmVkaWN0ZWQsIDEpKSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gNCkgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIiNmZWZlZmUiLCBoaWdoID0gIiMwMTY2NWUiKSArCiAgbGFicygKICAgIHRpdGxlID0gIlByZWRpY3RlZCBNb3NxdWl0byBDb3VudCBieSBHcmVlbm5lc3MgTGV2ZWwgYW5kIFRyYXAgVHlwZSIsCiAgICB4ID0gIlVyYmFuIEdyZWVubmVzcyBMZXZlbCIsCiAgICB5ID0gIlRyYXAgVHlwZSIsCiAgICBmaWxsID0gIlByZWRpY3RlZFxuQWJ1bmRhbmNlIgogICkgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMikpCgoKYGBgCk1vc3F1aXRvIGFidW5kYW5jZSByaXNlcyBtYXJrZWRseSB3aXRoIGluY3JlYXNpbmcgdXJiYW4gZ3JlZW5uZXNzLCByZWdhcmRsZXNzIG9mIHRoZSB0cmFwIHR5cGUgdXNlZC4KVGhlIG1vZGVsIHByZWRpY3RzIHJvdWdobHkgZml2ZSB0aW1lcyBtb3JlIG1vc3F1aXRvZXMgaW4gaGlnaGx5IHZlZ2V0YXRlZCBhcmVhcyB0aGFuIGluIGxvdy1ncmVlbm5lc3Mgem9uZXMsIGhpZ2hsaWdodGluZyB0aGUgZWNvbG9naWNhbCBpbXBvcnRhbmNlIG9mIHZlZ2V0YXRpb24gaW4gbW9zcXVpdG8gZGlzdHJpYnV0aW9uLgoKCgoKCmBgYHtyfQpkZl9wcmVkIDwtIGRmICU+JQogIG11dGF0ZSgKICAgIFByZWRpY3RlZCA9IHByZWRpY3QobW9kZWxfYWJ1bmRhbmNlLCB0eXBlID0gInJlc3BvbnNlIiksCiAgICBPYnNlcnZlZCA9IE1vc3F1aXRvX2FidW5kYW5jZQogICkKCgpnZ3Bsb3QoZGZfcHJlZCwgYWVzKHggPSBQcmVkaWN0ZWQsIHkgPSBPYnNlcnZlZCkpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC40LCBzaXplID0gMikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG9yID0gIiMwMTY2NWUiLCBzZSA9IFRSVUUpICsKICBsYWJzKAogICAgdGl0bGUgPSAiTW9kZWwgRml0OiBQcmVkaWN0ZWQgdnMgT2JzZXJ2ZWQgTW9zcXVpdG8gQWJ1bmRhbmNlIiwKICAgIHggPSAiUHJlZGljdGVkIEFidW5kYW5jZSAoTW9kZWwpIiwKICAgIHkgPSAiT2JzZXJ2ZWQgQWJ1bmRhbmNlIChEYXRhKSIKICApICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KQoKYGBgCgoKCgpgYGB7cn0KZGYgJT4lCiAgZ3JvdXBfYnkoR3JlZW5fbGV2ZWwsIE1vc3F1aXRvX3NwZWNpZXMpICU+JQogIHN1bW1hcmlzZShNZWFuX2FidW5kYW5jZSA9IG1lYW4oTW9zcXVpdG9fYWJ1bmRhbmNlKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZmFjdG9yKEdyZWVuX2xldmVsKSwgeSA9IE1lYW5fYWJ1bmRhbmNlLCBmaWxsID0gTW9zcXVpdG9fc3BlY2llcykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZmlsbCIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiUmVsYXRpdmUgTW9zcXVpdG8gU3BlY2llcyBDb21wb3NpdGlvbiBieSBHcmVlbm5lc3MgTGV2ZWwiLAogICAgeCA9ICJVcmJhbiBHcmVlbm5lc3MgTGV2ZWwiLAogICAgeSA9ICJQcm9wb3J0aW9uIG9mIFRvdGFsIEFidW5kYW5jZSIKICApICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KQoKYGBgCgoKYGBge3J9CgpkZiAlPiUKICBtdXRhdGUoTW9udGggPSBtb250aChTYW1wbGluZ19kYXRlLCBsYWJlbCA9IFRSVUUsIGFiYnIgPSBUUlVFKSkgJT4lCiAgZ3JvdXBfYnkoTW9udGgpICU+JQogIHN1bW1hcmlzZShNZWFuX2FidW5kYW5jZSA9IG1lYW4oTW9zcXVpdG9fYWJ1bmRhbmNlKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gTW9udGgsIHkgPSBNZWFuX2FidW5kYW5jZSwgZ3JvdXAgPSAxKSkgKwogIGdlb21fbGluZShzaXplID0gMS4yLCBjb2xvciA9ICIjMDE2NjVlIikgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIsIGNvbG9yID0gIiMwMTY2NWUiKSArCiAgbGFicygKICAgIHRpdGxlID0gIlNlYXNvbmFsIFRyZW5kIGluIE1vc3F1aXRvIEFidW5kYW5jZSIsCiAgICB4ID0gIk1vbnRoIiwKICAgIHkgPSAiQXZlcmFnZSBBYnVuZGFuY2UiCiAgKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkKCgpgYGAKCgoKCmBgYHtyfQpkZiAlPiUKICBtdXRhdGUoTW9udGggPSBtb250aChTYW1wbGluZ19kYXRlLCBsYWJlbCA9IFRSVUUsIGFiYnIgPSBUUlVFKSkgJT4lCiAgZ3JvdXBfYnkoQ2l0eSwgTW9udGgpICU+JQogIHN1bW1hcmlzZShNZWFuX2FidW5kYW5jZSA9IG1lYW4oTW9zcXVpdG9fYWJ1bmRhbmNlLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBNb250aCwgeSA9IE1lYW5fYWJ1bmRhbmNlLCBncm91cCA9IDEpKSArCiAgZ2VvbV9saW5lKGNvbG9yID0gIiMwMTY2NWUiLCBzaXplID0gMS4yKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICIjMDE2NjVlIiwgc2l6ZSA9IDIpICsKICBmYWNldF93cmFwKH4gQ2l0eSwgbmNvbCA9IDIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiU2Vhc29uYWwgVHJlbmRzIGluIE1vc3F1aXRvIEFidW5kYW5jZSBieSBDaXR5IiwKICAgIHggPSAiTW9udGgiLAogICAgeSA9ICJBdmVyYWdlIE1vc3F1aXRvIEFidW5kYW5jZSIKICApICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNiksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSkKICApCgpgYGAKCgoKCmBgYHtyfQpkZiAlPiUKICBtdXRhdGUoTW9udGggPSBtb250aChTYW1wbGluZ19kYXRlLCBsYWJlbCA9IFRSVUUsIGFiYnIgPSBUUlVFKSkgJT4lCiAgZ3JvdXBfYnkoQ2l0eSwgTW9udGgpICU+JQogIHN1bW1hcmlzZShNZWFuX2FidW5kYW5jZSA9IG1lYW4oTW9zcXVpdG9fYWJ1bmRhbmNlLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBNb250aCwgeSA9IE1lYW5fYWJ1bmRhbmNlLCBjb2xvciA9IENpdHksIGdyb3VwID0gQ2l0eSkpICsKICBnZW9tX2xpbmUoc2l6ZSA9IDEuMikgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiU2Vhc29uYWwgVHJlbmRzIGluIE1vc3F1aXRvIEFidW5kYW5jZSBieSBDaXR5IiwKICAgIHggPSAiTW9udGgiLAogICAgeSA9ICJBdmVyYWdlIE1vc3F1aXRvIEFidW5kYW5jZSIsCiAgICBjb2xvciA9ICJDaXR5IgogICkgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2KSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iCiAgKQoKCmBgYAoKCmBgYHtyfQpkZiAlPiUKICBtdXRhdGUoTW9udGggPSBtb250aChTYW1wbGluZ19kYXRlLCBsYWJlbCA9IFRSVUUsIGFiYnIgPSBUUlVFKSkgJT4lCiAgZ3JvdXBfYnkoTW9zcXVpdG9fc3BlY2llcywgTW9udGgpICU+JQogIHN1bW1hcmlzZShNZWFuX2FidW5kYW5jZSA9IG1lYW4oTW9zcXVpdG9fYWJ1bmRhbmNlLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBNb250aCwgeSA9IE1lYW5fYWJ1bmRhbmNlLCBjb2xvciA9IE1vc3F1aXRvX3NwZWNpZXMsIGdyb3VwID0gTW9zcXVpdG9fc3BlY2llcykpICsKICBnZW9tX3BvaW50KHNpemUgPSAyKSArCiAgZ2VvbV9zbW9vdGgoc2UgPSBGQUxTRSwgbGluZXdpZHRoID0gMS4yLCBtZXRob2QgPSAibG9lc3MiKSArCiAgbGFicygKICAgIHRpdGxlID0gIlNlYXNvbmFsIFRyZW5kcyBpbiBNb3NxdWl0byBBYnVuZGFuY2UgYnkgU3BlY2llcyIsCiAgICB4ID0gIk1vbnRoIiwKICAgIHkgPSAiQXZlcmFnZSBNb3NxdWl0byBBYnVuZGFuY2UiLAogICAgY29sb3IgPSAiU3BlY2llcyIKICApICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNiksCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIgogICkKCmBgYAoKCgpgYGB7cn0KCmRmJERhdGUgPC0gYXMuRGF0ZShkZiRTYW1wbGluZ19kYXRlLCBmb3JtYXQgPSAiJVktJW0tJWQiKQoKIyBDcmVhdGUgdGhlIG1vbnRobHkgdHJlbmQgcGxvdApkZiAlPiUKICBtdXRhdGUoTW9udGggPSBtb250aChEYXRlLCBsYWJlbCA9IFRSVUUsIGFiYnIgPSBUUlVFKSkgJT4lCiAgZ3JvdXBfYnkoTW9zcXVpdG9fc3BlY2llcywgTW9udGgpICU+JQogIHN1bW1hcmlzZShNZWFuX2FidW5kYW5jZSA9IG1lYW4oTW9zcXVpdG9fYWJ1bmRhbmNlLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBNb250aCwgeSA9IE1lYW5fYWJ1bmRhbmNlLCBjb2xvciA9IE1vc3F1aXRvX3NwZWNpZXMsIGdyb3VwID0gTW9zcXVpdG9fc3BlY2llcykpICsKICBnZW9tX2xpbmUobGluZXdpZHRoID0gMS4yKSArCiAgZ2VvbV9wb2ludChzaXplID0gMikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJNb250aGx5IFRyZW5kcyBpbiBNb3NxdWl0byBBYnVuZGFuY2UgYnkgU3BlY2llcyIsCiAgICB4ID0gIk1vbnRoIiwKICAgIHkgPSAiQXZlcmFnZSBNb3NxdWl0byBBYnVuZGFuY2UiLAogICAgY29sb3IgPSAiU3BlY2llcyIKICApICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNiksCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIgogICkKCmBgYAoKCgpgYGB7cn0KCiMgQ3JlYXRlIGZhY2V0ZWQgcGxvdCBieSBzcGVjaWVzCmRmICU+JQogIG11dGF0ZShNb250aCA9IG1vbnRoKERhdGUsIGxhYmVsID0gVFJVRSwgYWJiciA9IFRSVUUpKSAlPiUKICBncm91cF9ieShNb3NxdWl0b19zcGVjaWVzLCBNb250aCkgJT4lCiAgc3VtbWFyaXNlKE1lYW5fYWJ1bmRhbmNlID0gbWVhbihNb3NxdWl0b19hYnVuZGFuY2UsIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIGdncGxvdChhZXMoeCA9IE1vbnRoLCB5ID0gTWVhbl9hYnVuZGFuY2UsIGdyb3VwID0gMSkpICsKICBnZW9tX2xpbmUoY29sb3IgPSAiIzJDN0JCNiIsIGxpbmV3aWR0aCA9IDEuMikgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiIzJDN0JCNiIsIHNpemUgPSAyKSArCiAgZmFjZXRfd3JhcCh+IE1vc3F1aXRvX3NwZWNpZXMsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgbGFicygKICAgIHRpdGxlID0gIk1vbnRobHkgVHJlbmRzIGluIE1vc3F1aXRvIEFidW5kYW5jZSBieSBTcGVjaWVzIiwKICAgIHggPSAiTW9udGgiLAogICAgeSA9ICJBdmVyYWdlIE1vc3F1aXRvIEFidW5kYW5jZSIKICApICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNiwgaGp1c3QgPSAwLjUpLAogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41KSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIgogICkKCmBgYAoKCgoKYGBge3J9CmdncGxvdChkZiwgYWVzKHggPSBUcmFwX3R5cGUsIHkgPSBNb3NxdWl0b19hYnVuZGFuY2UsIGZpbGwgPSBUcmFwX3R5cGUpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuYWxwaGEgPSAwLjIpICsKICBmYWNldF93cmFwKH4gQ2l0eSkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIE1vc3F1aXRvIEFidW5kYW5jZSBieSBUcmFwIFR5cGUgYW5kIENpdHkiLAogICAgeCA9ICJUcmFwIFR5cGUiLCB5ID0gIk1vc3F1aXRvIEFidW5kYW5jZSIKICApICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpCiAgKQoKYGBgCgoKCg==